mirror of
https://github.com/NationalSecurityAgency/ghidra
synced 2024-06-30 23:04:52 +00:00
Compare commits
13 Commits
a3839b2213
...
b0f9f91b5a
Author | SHA1 | Date | |
---|---|---|---|
|
b0f9f91b5a | ||
|
93eed8011c | ||
|
3cffe5c168 | ||
|
b78c975ee3 | ||
|
e604b25417 | ||
|
24f9e4dbfb | ||
|
7392d5bab2 | ||
|
10ee3d83de | ||
|
fce0b863ce | ||
|
6e9a318b04 | ||
|
a2d5caae06 | ||
|
1dc20547a0 | ||
|
b02bd6e44e |
|
@ -21,20 +21,35 @@ import ghidra.app.util.bin.StructConverter;
|
|||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* An OMF value that is either 2 or 4 bytes
|
||||
*/
|
||||
public class Omf2or4 implements StructConverter {
|
||||
|
||||
private int length;
|
||||
private long value;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Omf2or4}
|
||||
*
|
||||
* @param length 2 or 4
|
||||
* @param value The 2 or 4 byte value
|
||||
*/
|
||||
public Omf2or4(int length, long value) {
|
||||
this.length = length;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the length of the value (2 or 4)}
|
||||
*/
|
||||
public int length() {
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the value}
|
||||
*/
|
||||
public long value() {
|
||||
return value;
|
||||
}
|
||||
|
|
|
@ -15,8 +15,16 @@
|
|||
*/
|
||||
package ghidra.app.util.bin.format.omf;
|
||||
|
||||
/**
|
||||
* An {@link Exception} used to indicate there was a problem parsing an OMF record
|
||||
*/
|
||||
public class OmfException extends Exception {
|
||||
|
||||
/**
|
||||
* Creates a new {@link OmfException}
|
||||
*
|
||||
* @param message The exception message
|
||||
*/
|
||||
public OmfException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
|
|
@ -21,20 +21,35 @@ import ghidra.app.util.bin.StructConverter;
|
|||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* An OMF index that is either 1 or 2 bytes
|
||||
*/
|
||||
public class OmfIndex implements StructConverter {
|
||||
|
||||
private int length;
|
||||
private int value;
|
||||
|
||||
/**
|
||||
* Creates a new {@link OmfIndex}
|
||||
*
|
||||
* @param length 1 or 2
|
||||
* @param value The 1 or 2 byte index value
|
||||
*/
|
||||
public OmfIndex(int length, int value) {
|
||||
this.length = length;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the length of the index (1 or 2)}
|
||||
*/
|
||||
public int length() {
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the index value}
|
||||
*/
|
||||
public int value() {
|
||||
return value;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,9 @@ package ghidra.app.util.bin.format.omf;
|
|||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.omf.omf.OmfRecordTypes;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public class OmfObsoleteRecord extends OmfRecord {
|
||||
|
||||
|
@ -31,4 +34,9 @@ public class OmfObsoleteRecord extends OmfRecord {
|
|||
readRecordHeader(reader);
|
||||
reader.setPointerIndex(reader.getPointerIndex() + getRecordLength());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
return OmfUtils.toOmfRecordDataType(this, OmfRecordTypes.getName(recordType));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,258 +16,111 @@
|
|||
package ghidra.app.util.bin.format.omf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* A generic OMF record
|
||||
*/
|
||||
public abstract class OmfRecord implements StructConverter {
|
||||
public final static byte RHEADR = (byte) 0x6E; // Obsolete
|
||||
public final static byte REGINT = (byte) 0x70; // Obsolete
|
||||
public final static byte REDATA = (byte) 0x72; // Obsolete
|
||||
public final static byte RIDATA = (byte) 0x74; // Obsolete
|
||||
public final static byte OVLDEF = (byte) 0x76; // Obsolete
|
||||
public final static byte ENDREC = (byte) 0x78; // Obsolete
|
||||
public final static byte BLKDEF = (byte) 0x7A; // Obsolete
|
||||
public final static byte BLKEND = (byte) 0x7C; // Obsolete
|
||||
public final static byte DEBSYM = (byte) 0x7E; // Obsolete
|
||||
public final static byte THEADR = (byte) 0x80;
|
||||
public final static byte LHEADR = (byte) 0x82;
|
||||
public final static byte PEDATA = (byte) 0x84; // Obsolete
|
||||
public final static byte PIDATA = (byte) 0x86; // Obsolete
|
||||
public final static byte COMENT = (byte) 0x88;
|
||||
public final static byte MODEND = (byte) 0x8A;
|
||||
public final static byte EXTDEF = (byte) 0x8C;
|
||||
public final static byte TYPDEF = (byte) 0x8E; // Obsolete
|
||||
public final static byte PUBDEF = (byte) 0x90;
|
||||
public final static byte LOCSYM = (byte) 0x92; // Obsolete
|
||||
public final static byte LINNUM = (byte) 0x94;
|
||||
public final static byte LNAMES = (byte) 0x96;
|
||||
public final static byte SEGDEF = (byte) 0x98;
|
||||
public final static byte GRPDEF = (byte) 0x9A;
|
||||
public final static byte FIXUPP = (byte) 0x9C;
|
||||
public final static byte LEDATA = (byte) 0xA0;
|
||||
public final static byte LIDATA = (byte) 0xA2;
|
||||
public final static byte LIBHED = (byte) 0xA4; // Obsolete
|
||||
public final static byte LIBNAM = (byte) 0xA6; // Obsolete
|
||||
public final static byte LIBLOC = (byte) 0xA8; // Obsolete
|
||||
public final static byte LIBDIC = (byte) 0xAA; // Obsolete
|
||||
public final static byte COMDEF = (byte) 0xB0;
|
||||
public final static byte BAKPAT = (byte) 0xB2;
|
||||
public final static byte LEXTDEF = (byte) 0xB4;
|
||||
public final static byte LPUBDEF = (byte) 0xB6;
|
||||
public final static byte LCOMDEF = (byte) 0xB8;
|
||||
public final static byte CEXTDEF = (byte) 0xBC;
|
||||
public final static byte COMDAT = (byte) 0xC2;
|
||||
public final static byte LINSYM = (byte) 0xC4;
|
||||
public final static byte ALIAS = (byte) 0xC6;
|
||||
public final static byte NBKPAT = (byte) 0xC8;
|
||||
public final static byte LLNAMES = (byte) 0xCA;
|
||||
public final static byte VERNUM = (byte) 0xCC;
|
||||
public final static byte VENDEXT = (byte) 0xCE;
|
||||
public final static byte START = (byte) 0xF0;
|
||||
public final static byte END = (byte) 0xF1;
|
||||
|
||||
protected static final String CATEGORY_PATH = "/OMF";
|
||||
|
||||
protected byte recordType;
|
||||
protected int recordType;
|
||||
protected int recordLength;
|
||||
protected long recordOffset;
|
||||
protected byte checkSum;
|
||||
|
||||
public byte getRecordType() {
|
||||
return recordType;
|
||||
}
|
||||
|
||||
public int getRecordLength() {
|
||||
return recordLength;
|
||||
}
|
||||
|
||||
public long getRecordOffset() {
|
||||
return recordOffset;
|
||||
}
|
||||
protected long recordOffset;
|
||||
|
||||
/**
|
||||
* Reads the record header (type and length fields)
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of the record
|
||||
* @throws IOException if an IO-related problem occurred
|
||||
*/
|
||||
public void readRecordHeader(BinaryReader reader) throws IOException {
|
||||
recordOffset = reader.getPointerIndex();
|
||||
recordType = reader.readNextByte();
|
||||
recordLength = reader.readNextShort() & 0xffff;
|
||||
recordType = reader.readNextUnsignedByte();
|
||||
recordLength = reader.readNextUnsignedShort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the record checksum
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of the record checksum
|
||||
* @throws IOException if an IO-related problem occurred
|
||||
*/
|
||||
public void readCheckSumByte(BinaryReader reader) throws IOException {
|
||||
checkSum = reader.readNextByte();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the record type}
|
||||
*/
|
||||
public int getRecordType() {
|
||||
return recordType;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the record length}
|
||||
*/
|
||||
public int getRecordLength() {
|
||||
return recordLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the record offset}
|
||||
*/
|
||||
public long getRecordOffset() {
|
||||
return recordOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the record's checksum
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of record
|
||||
* @return The record's checksum
|
||||
* @throws IOException if an IO-related error occurred
|
||||
*/
|
||||
public byte calcCheckSum(BinaryReader reader) throws IOException {
|
||||
byte res = reader.readNextByte();
|
||||
res += reader.readNextByte();
|
||||
res += reader.readNextByte(); // Sum the record header bytes
|
||||
for (int i = 0; i < recordLength; ++i)
|
||||
for (int i = 0; i < recordLength; ++i) {
|
||||
res += reader.readNextByte();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the record's checksum
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of the record
|
||||
* @return True if the checksum is valid; otherwise, false
|
||||
* @throws IOException if an IO-related error occurred
|
||||
*/
|
||||
public boolean validCheckSum(BinaryReader reader) throws IOException {
|
||||
if (checkSum == 0)
|
||||
return true; // Sum compilers just set this to zero
|
||||
if (checkSum == 0) {
|
||||
// Some compilers just set this to zero
|
||||
return true;
|
||||
}
|
||||
return (calcCheckSum(reader) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return true if this record has big fields; otherwise, false}
|
||||
*/
|
||||
public boolean hasBigFields() {
|
||||
return ((recordType & 1) != 0);
|
||||
}
|
||||
|
||||
public static int readInt1Or2(BinaryReader reader, boolean isBig) throws IOException {
|
||||
if (isBig)
|
||||
return (reader.readNextShort() & 0xffff);
|
||||
return (reader.readNextByte() & 0xff);
|
||||
}
|
||||
|
||||
public static Omf2or4 readInt2Or4(BinaryReader reader, boolean isBig) throws IOException {
|
||||
if (isBig) {
|
||||
return new Omf2or4(4, reader.readNextInt());
|
||||
}
|
||||
return new Omf2or4(2, reader.readNextUnsignedShort());
|
||||
}
|
||||
|
||||
public static OmfIndex readIndex(BinaryReader reader) throws IOException {
|
||||
int length;
|
||||
int indexWord;
|
||||
byte firstByte = reader.readNextByte();
|
||||
if ((firstByte & 0x80) != 0) {
|
||||
indexWord = (firstByte & 0x7f) * 0x100 + (reader.readNextByte() & 0xff);
|
||||
length = 2;
|
||||
}
|
||||
else {
|
||||
indexWord = firstByte;
|
||||
length = 1;
|
||||
}
|
||||
return new OmfIndex(length, indexWord);
|
||||
}
|
||||
|
||||
public static OmfRecord readRecord(BinaryReader reader) throws IOException, OmfException {
|
||||
byte type = reader.peekNextByte();
|
||||
type &= 0xfe; // Mask off the least significant bit (16/32 bit flag)
|
||||
return switch (type) {
|
||||
case THEADR:
|
||||
case LHEADR:
|
||||
yield new OmfFileHeader(reader);
|
||||
case COMENT:
|
||||
yield new OmfCommentRecord(reader);
|
||||
case MODEND:
|
||||
yield new OmfModuleEnd(reader);
|
||||
case EXTDEF:
|
||||
yield new OmfExternalSymbol(reader, false);
|
||||
case PUBDEF:
|
||||
yield new OmfSymbolRecord(reader, false);
|
||||
case LNAMES:
|
||||
yield new OmfNamesRecord(reader);
|
||||
case SEGDEF:
|
||||
yield new OmfSegmentHeader(reader);
|
||||
case GRPDEF:
|
||||
yield new OmfGroupRecord(reader);
|
||||
case FIXUPP:
|
||||
yield new OmfFixupRecord(reader);
|
||||
case LEDATA:
|
||||
yield new OmfEnumeratedData(reader);
|
||||
case LIDATA:
|
||||
yield new OmfIteratedData(reader);
|
||||
case COMDEF:
|
||||
yield new OmfComdefRecord(reader, false);
|
||||
case LEXTDEF:
|
||||
yield new OmfExternalSymbol(reader, true);
|
||||
case LPUBDEF:
|
||||
yield new OmfSymbolRecord(reader, true);
|
||||
case LCOMDEF:
|
||||
yield new OmfComdefRecord(reader, true);
|
||||
case CEXTDEF:
|
||||
yield new OmfComdatExternalSymbol(reader);
|
||||
case RHEADR:
|
||||
case REGINT:
|
||||
case REDATA:
|
||||
case RIDATA:
|
||||
case OVLDEF:
|
||||
case ENDREC:
|
||||
case BLKDEF:
|
||||
case BLKEND:
|
||||
case DEBSYM:
|
||||
case LINNUM:
|
||||
case PEDATA:
|
||||
case PIDATA:
|
||||
case LIBHED:
|
||||
case LIBNAM:
|
||||
case LIBLOC:
|
||||
case LIBDIC:
|
||||
yield new OmfObsoleteRecord(reader);
|
||||
case LOCSYM:
|
||||
case TYPDEF:
|
||||
case COMDAT:
|
||||
case LINSYM:
|
||||
case ALIAS:
|
||||
case BAKPAT:
|
||||
case NBKPAT:
|
||||
case LLNAMES:
|
||||
case VERNUM:
|
||||
case VENDEXT:
|
||||
yield new OmfUnsupportedRecord(reader);
|
||||
default:
|
||||
yield new OmfUnknownRecord(reader);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the OMF string format: 1-byte length, followed by that many ascii characters
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of the string
|
||||
* @return the read OMF string
|
||||
* @throws IOException if an IO-related error occurred
|
||||
*/
|
||||
public static OmfString readString(BinaryReader reader) throws IOException {
|
||||
int count = reader.readNextByte() & 0xff;
|
||||
return new OmfString(count, reader.readNextAsciiString(count));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the given record type
|
||||
*
|
||||
* @param type The record type
|
||||
* @return The name of the given record type
|
||||
*/
|
||||
public final static String getRecordName(int type) {
|
||||
for (Field field : OmfRecord.class.getDeclaredFields()) {
|
||||
int modifiers = field.getModifiers();
|
||||
if (Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers)) {
|
||||
try {
|
||||
Byte value = (Byte) field.get(null);
|
||||
if (type == value) {
|
||||
return field.getName();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return "<UNKNOWN>";
|
||||
}
|
||||
@Override
|
||||
public abstract DataType toDataType() throws DuplicateNameException, IOException;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("name: %s, type: 0x%x, offset: 0x%x, length: 0x%x",
|
||||
getRecordName(recordType & (byte) 0xfe), recordType, recordOffset, recordLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType(getRecordName(getRecordType()), 0);
|
||||
struct.add(BYTE, "type", null);
|
||||
struct.add(WORD, "length", null);
|
||||
struct.add(new ArrayDataType(BYTE, getRecordLength() - 1, 1), "contents", null);
|
||||
struct.add(BYTE, "checksum", null);
|
||||
|
||||
struct.setCategoryPath(new CategoryPath(CATEGORY_PATH));
|
||||
return struct;
|
||||
return String.format("type: 0x%x, offset: 0x%x, length: 0x%x", recordType, recordOffset,
|
||||
recordLength);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,20 +21,35 @@ import ghidra.app.util.bin.StructConverter;
|
|||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* An variable length OMF string
|
||||
*/
|
||||
public class OmfString implements StructConverter {
|
||||
|
||||
private int length;
|
||||
private String str;
|
||||
|
||||
/**
|
||||
* Creates a new {@link OmfString}
|
||||
*
|
||||
* @param length The length of the string
|
||||
* @param str The string
|
||||
*/
|
||||
public OmfString(int length, String str) {
|
||||
this.length = length;
|
||||
this.str = str;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the length of the string}
|
||||
*/
|
||||
public int length() {
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the string}
|
||||
*/
|
||||
public String str() {
|
||||
return str;
|
||||
}
|
||||
|
@ -48,7 +63,7 @@ public class OmfString implements StructConverter {
|
|||
StructureDataType struct = new StructureDataType("OmfString", 0);
|
||||
struct.add(BYTE, "length", "");
|
||||
struct.add(new StringDataType(), length, "str", null);
|
||||
struct.setCategoryPath(new CategoryPath(OmfRecord.CATEGORY_PATH));
|
||||
struct.setCategoryPath(new CategoryPath(OmfUtils.CATEGORY_PATH));
|
||||
return struct;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,13 @@ package ghidra.app.util.bin.format.omf;
|
|||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.omf.omf.OmfRecordTypes;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* An unknown OMF record
|
||||
*/
|
||||
public class OmfUnknownRecord extends OmfRecord {
|
||||
|
||||
/**
|
||||
|
@ -31,4 +37,9 @@ public class OmfUnknownRecord extends OmfRecord {
|
|||
readRecordHeader(reader);
|
||||
reader.setPointerIndex(reader.getPointerIndex() + getRecordLength());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
return OmfUtils.toOmfRecordDataType(this, OmfRecordTypes.getName(recordType));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,17 +18,32 @@ package ghidra.app.util.bin.format.omf;
|
|||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* A known but currently unsupported OMF record
|
||||
*/
|
||||
public class OmfUnsupportedRecord extends OmfRecord {
|
||||
|
||||
private Class<?> recordTypesClass;
|
||||
|
||||
/**
|
||||
* Create a new {@link OmfUnsupportedRecord}
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of the record
|
||||
* @param recordTypesClass The class that contains accessible OMF type fields
|
||||
* @throws IOException If an IO-related error occurred
|
||||
*/
|
||||
public OmfUnsupportedRecord(BinaryReader reader) throws IOException {
|
||||
public OmfUnsupportedRecord(BinaryReader reader, Class<?> recordTypesClass) throws IOException {
|
||||
this.recordTypesClass = recordTypesClass;
|
||||
readRecordHeader(reader);
|
||||
reader.setPointerIndex(reader.getPointerIndex() + getRecordLength());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
return OmfUtils.toOmfRecordDataType(this,
|
||||
OmfUtils.getRecordName(recordType, recordTypesClass));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.omf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.*;
|
||||
|
||||
/**
|
||||
* Utility class for OMF-based file formats
|
||||
*/
|
||||
public class OmfUtils {
|
||||
|
||||
/** Data type category */
|
||||
public static final String CATEGORY_PATH = "/OMF";
|
||||
|
||||
public static Omf2or4 readInt2Or4(BinaryReader reader, boolean isBig) throws IOException {
|
||||
return isBig ? new Omf2or4(4, reader.readNextInt())
|
||||
: new Omf2or4(2, reader.readNextUnsignedShort());
|
||||
}
|
||||
|
||||
public static OmfIndex readIndex(BinaryReader reader) throws IOException {
|
||||
int length;
|
||||
int indexWord;
|
||||
byte firstByte = reader.readNextByte();
|
||||
if ((firstByte & 0x80) != 0) {
|
||||
indexWord = (firstByte & 0x7f) * 0x100 + (reader.readNextByte() & 0xff);
|
||||
length = 2;
|
||||
}
|
||||
else {
|
||||
indexWord = firstByte;
|
||||
length = 1;
|
||||
}
|
||||
return new OmfIndex(length, indexWord);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the OMF string format: 1-byte length, followed by that many ascii characters
|
||||
*
|
||||
* @param reader A {@link BinaryReader} positioned at the start of the string
|
||||
* @return the read OMF string
|
||||
* @throws IOException if an IO-related error occurred
|
||||
*/
|
||||
public static OmfString readString(BinaryReader reader) throws IOException {
|
||||
int count = reader.readNextUnsignedByte();
|
||||
return new OmfString(count, reader.readNextAsciiString(count));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the given record type
|
||||
*
|
||||
* @param type The record type
|
||||
* @param recordTypesClass The class that contains accessible OMF type fields
|
||||
* @return The name of the given record type
|
||||
*/
|
||||
public final static String getRecordName(int type, Class<?> recordTypesClass) {
|
||||
for (Field field : recordTypesClass.getDeclaredFields()) {
|
||||
int modifiers = field.getModifiers();
|
||||
if (Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers)) {
|
||||
try {
|
||||
Integer value = (Integer) field.get(null);
|
||||
if (type == value) {
|
||||
return field.getName();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return "<UNKNOWN>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given {@link OmfRecord} to a generic OMF record {@link DataType}
|
||||
*
|
||||
* @param record The OMF record to convert
|
||||
* @param name The name of the OMF record
|
||||
* @return A {@link DataType} for the given OMF record
|
||||
*/
|
||||
public static DataType toOmfRecordDataType(OmfRecord record, String name) {
|
||||
StructureDataType struct = new StructureDataType(name, 0);
|
||||
struct.add(ByteDataType.dataType, "type", null);
|
||||
struct.add(WordDataType.dataType, "length", null);
|
||||
struct.add(new ArrayDataType(ByteDataType.dataType, record.getRecordLength() - 1, 1),
|
||||
"contents", null);
|
||||
struct.add(ByteDataType.dataType, "checksum", null);
|
||||
|
||||
struct.setCategoryPath(new CategoryPath(OmfUtils.CATEGORY_PATH));
|
||||
return struct;
|
||||
}
|
||||
}
|
|
@ -13,13 +13,15 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.omf;
|
||||
package ghidra.app.util.bin.format.omf.omf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.omf.OmfIndex;
|
||||
import ghidra.app.util.bin.format.omf.OmfUtils;
|
||||
|
||||
public class OmfComdatExternalSymbol extends OmfExternalSymbol {
|
||||
|
||||
|
@ -32,8 +34,8 @@ public class OmfComdatExternalSymbol extends OmfExternalSymbol {
|
|||
|
||||
long max = reader.getPointerIndex() + getRecordLength() - 1;
|
||||
while (reader.getPointerIndex() < max) {
|
||||
OmfIndex nameIndex = OmfRecord.readIndex(reader);
|
||||
OmfIndex type = OmfRecord.readIndex(reader);
|
||||
OmfIndex nameIndex = OmfUtils.readIndex(reader);
|
||||
OmfIndex type = OmfUtils.readIndex(reader);
|
||||
externalLookups.add(new ExternalLookup(nameIndex.value(), type.value()));
|
||||
}
|
||||
|
|
@ -13,11 +13,12 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.omf;
|
||||
package ghidra.app.util.bin.format.omf.omf;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.omf.*;
|
||||
|
||||
public class OmfComdefRecord extends OmfExternalSymbol {
|
||||
|
||||
|
@ -27,8 +28,8 @@ public class OmfComdefRecord extends OmfExternalSymbol {
|
|||
|
||||
long max = reader.getPointerIndex() + getRecordLength() - 1;
|
||||
while (reader.getPointerIndex() < max) {
|
||||
OmfString name = OmfRecord.readString(reader);
|
||||
OmfIndex typeIndex = OmfRecord.readIndex(reader);
|
||||
OmfString name = OmfUtils.readString(reader);
|
||||
OmfIndex typeIndex = OmfUtils.readIndex(reader);
|
||||
byte dataType = reader.readNextByte();
|
||||
int byteLength = 0;
|
||||
if (dataType == 0x61) { // FAR data, reads numElements and elSize
|
|
@ -13,12 +13,13 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.omf;
|
||||
package ghidra.app.util.bin.format.omf.omf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.omf.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
|
@ -51,7 +52,7 @@ public class OmfCommentRecord extends OmfRecord {
|
|||
value = new OmfString(bytes.length, new String(bytes, StandardCharsets.US_ASCII)); // assuming ASCII
|
||||
break;
|
||||
case COMMENT_CLASS_LIBMOD:
|
||||
value = readString(reader);
|
||||
value = OmfUtils.readString(reader);
|
||||
break;
|
||||
default:
|
||||
reader.setPointerIndex(reader.getPointerIndex() + getRecordLength() - 3);
|
||||
|
@ -76,7 +77,7 @@ public class OmfCommentRecord extends OmfRecord {
|
|||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
int strlen = getRecordLength() - 3;
|
||||
|
||||
StructureDataType struct = new StructureDataType(getRecordName(getRecordType()), 0);
|
||||
StructureDataType struct = new StructureDataType(OmfRecordTypes.getName(recordType), 0);
|
||||
struct.add(BYTE, "type", null);
|
||||
struct.add(WORD, "length", "");
|
||||
struct.add(BYTE, "comment_type", null);
|
||||
|
@ -86,7 +87,7 @@ public class OmfCommentRecord extends OmfRecord {
|
|||
}
|
||||
struct.add(BYTE, "checksum", null);
|
||||
|
||||
struct.setCategoryPath(new CategoryPath(OmfRecord.CATEGORY_PATH));
|
||||
struct.setCategoryPath(new CategoryPath(OmfUtils.CATEGORY_PATH));
|
||||
return struct;
|
||||
}
|
||||
}
|
|
@ -13,11 +13,12 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.omf;
|
||||
package ghidra.app.util.bin.format.omf.omf;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.omf.*;
|
||||
|
||||
/**
|
||||
* Object representing data loaded directly into the final image.
|
|
@ -13,11 +13,14 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.omf;
|
||||
package ghidra.app.util.bin.format.omf.omf;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.omf.OmfUtils;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public class OmfEnumeratedData extends OmfData {
|
||||
private long streamOffset; // Position in stream where data starts
|
||||
|
@ -26,8 +29,8 @@ public class OmfEnumeratedData extends OmfData {
|
|||
public OmfEnumeratedData(BinaryReader reader) throws IOException {
|
||||
readRecordHeader(reader);
|
||||
long start = reader.getPointerIndex();
|
||||
segmentIndex = OmfRecord.readIndex(reader);
|
||||
dataOffset = OmfRecord.readInt2Or4(reader, hasBigFields());
|
||||
segmentIndex = OmfUtils.readIndex(reader);
|
||||
dataOffset = OmfUtils.readInt2Or4(reader, hasBigFields());
|
||||
streamOffset = reader.getPointerIndex();
|
||||
streamLength = getRecordLength() - 1 - (int) (streamOffset - start);
|
||||
reader.setPointerIndex(streamOffset + streamLength); // Skip over the data when reading header
|
||||
|
@ -50,4 +53,9 @@ public class OmfEnumeratedData extends OmfData {
|
|||
public boolean isAllZeroes() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
return OmfUtils.toOmfRecordDataType(this, OmfRecordTypes.getName(recordType));
|
||||
}
|
||||
}
|
|
@ -13,13 +13,14 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.omf;
|
||||
package ghidra.app.util.bin.format.omf.omf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.omf.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
|
@ -42,8 +43,8 @@ public class OmfExternalSymbol extends OmfRecord {
|
|||
|
||||
long max = reader.getPointerIndex() + getRecordLength() - 1;
|
||||
while (reader.getPointerIndex() < max) {
|
||||
OmfString name = OmfRecord.readString(reader);
|
||||
OmfIndex type = OmfRecord.readIndex(reader);
|
||||
OmfString name = OmfUtils.readString(reader);
|
||||
OmfIndex type = OmfUtils.readIndex(reader);
|
||||
refs.add(new Reference(name, type));
|
||||
symbols.add(new OmfSymbol(name.str(), type.value(), 0, 0, 0));
|
||||
}
|
||||
|
@ -61,7 +62,7 @@ public class OmfExternalSymbol extends OmfRecord {
|
|||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType(getRecordName(getRecordType()), 0);
|
||||
StructureDataType struct = new StructureDataType(OmfRecordTypes.getName(recordType), 0);
|
||||
struct.add(BYTE, "type", null);
|
||||
struct.add(WORD, "length", null);
|
||||
for (Reference ref : refs) {
|
||||
|
@ -70,7 +71,7 @@ public class OmfExternalSymbol extends OmfRecord {
|
|||
}
|
||||
struct.add(BYTE, "checksum", null);
|
||||
|
||||
struct.setCategoryPath(new CategoryPath(OmfRecord.CATEGORY_PATH));
|
||||
struct.setCategoryPath(new CategoryPath(OmfUtils.CATEGORY_PATH));
|
||||
return struct;
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.omf;
|
||||
package ghidra.app.util.bin.format.omf.omf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
@ -21,6 +21,7 @@ import java.util.List;
|
|||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.format.omf.*;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
@ -45,7 +46,7 @@ public class OmfFileHeader extends OmfRecord {
|
|||
|
||||
public OmfFileHeader(BinaryReader reader) throws IOException {
|
||||
readRecordHeader(reader);
|
||||
objectName = readString(reader); // This is usually the source code filename
|
||||
objectName = OmfUtils.readString(reader); // This is usually the source code filename
|
||||
readCheckSumByte(reader);
|
||||
isLittleEndian = reader.isLittleEndian();
|
||||
}
|
||||
|
@ -269,14 +270,14 @@ public class OmfFileHeader extends OmfRecord {
|
|||
*/
|
||||
public static OmfFileHeader scan(BinaryReader reader, TaskMonitor monitor, boolean fastscan)
|
||||
throws IOException, OmfException {
|
||||
OmfRecord record = OmfRecord.readRecord(reader);
|
||||
OmfRecord record = OmfRecordFactory.readRecord(reader);
|
||||
if (!(record instanceof OmfFileHeader)) {
|
||||
throw new OmfException("Object file does not start with proper header");
|
||||
}
|
||||
OmfFileHeader header = (OmfFileHeader) record;
|
||||
|
||||
while (true) {
|
||||
record = OmfRecord.readRecord(reader);
|
||||
record = OmfRecordFactory.readRecord(reader);
|
||||
|
||||
if (monitor.isCancelled()) {
|
||||
break;
|
||||
|
@ -323,7 +324,7 @@ public class OmfFileHeader extends OmfRecord {
|
|||
*/
|
||||
public static OmfFileHeader parse(BinaryReader reader, TaskMonitor monitor, MessageLog log)
|
||||
throws IOException, OmfException {
|
||||
OmfRecord record = OmfRecord.readRecord(reader);
|
||||
OmfRecord record = OmfRecordFactory.readRecord(reader);
|
||||
if (!(record instanceof OmfFileHeader header)) {
|
||||
throw new OmfException("Object file does not start with proper header");
|
||||
}
|
||||
|
@ -331,7 +332,7 @@ public class OmfFileHeader extends OmfRecord {
|
|||
OmfData lastDataBlock = null;
|
||||
|
||||
while (true) {
|
||||
record = OmfRecord.readRecord(reader);
|
||||
record = OmfRecordFactory.readRecord(reader);
|
||||
header.records.add(record);
|
||||
|
||||
if (monitor.isCancelled()) {
|
||||
|
@ -392,7 +393,7 @@ public class OmfFileHeader extends OmfRecord {
|
|||
}
|
||||
else if (record instanceof OmfUnsupportedRecord) {
|
||||
// TODO: Should we always set lastDataBlock to null?
|
||||
if (record.getRecordType() == COMDAT) {
|
||||
if (record.getRecordType() == OmfRecordTypes.COMDAT) {
|
||||
lastDataBlock = null;
|
||||
}
|
||||
logRecord("Unsupported OMF record", record, log);
|
||||
|
@ -477,16 +478,14 @@ public class OmfFileHeader extends OmfRecord {
|
|||
* @throws IOException for problems reading bytes
|
||||
*/
|
||||
public static boolean checkMagicNumber(BinaryReader reader) throws IOException {
|
||||
byte first = reader.readNextByte();
|
||||
if ((first & 0xfc) != 0x80) {
|
||||
int type = reader.readNextUnsignedByte();
|
||||
type &= 0xfffffffe; // mask off the least significant bit (16/32 bit flag)
|
||||
if (type != OmfRecordTypes.THEADR && type != OmfRecordTypes.LHEADR) {
|
||||
return false;
|
||||
}
|
||||
int len = reader.readNextShort() & 0xffff;
|
||||
int stringlen = reader.readNextByte() & 0xff;
|
||||
if (len != stringlen + 2) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
int len = reader.readNextUnsignedShort();
|
||||
int stringlen = reader.readNextUnsignedByte();
|
||||
return len == stringlen + 2;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -504,13 +503,13 @@ public class OmfFileHeader extends OmfRecord {
|
|||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType(getRecordName(getRecordType()), 0);
|
||||
StructureDataType struct = new StructureDataType(OmfRecordTypes.getName(recordType), 0);
|
||||
struct.add(BYTE, "type", null);
|
||||
struct.add(WORD, "length", null);
|
||||
struct.add(objectName.toDataType(), "name", null);
|
||||
struct.add(BYTE, "checksum", null);
|
||||
|
||||
struct.setCategoryPath(new CategoryPath(OmfRecord.CATEGORY_PATH));
|
||||
struct.setCategoryPath(new CategoryPath(OmfUtils.CATEGORY_PATH));
|
||||
return struct;
|
||||
}
|
||||
}
|
|
@ -13,12 +13,15 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.omf;
|
||||
package ghidra.app.util.bin.format.omf.omf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.omf.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public class OmfFixupRecord extends OmfRecord {
|
||||
private final Subrecord[] subrecs;
|
||||
|
@ -27,7 +30,7 @@ public class OmfFixupRecord extends OmfRecord {
|
|||
/**
|
||||
* Read a Fixup record from the input reader
|
||||
* @param reader The actual reader
|
||||
* @throws IOException
|
||||
* @throws IOException if there was an IO-related error
|
||||
*/
|
||||
public OmfFixupRecord(BinaryReader reader) throws IOException {
|
||||
ArrayList<Subrecord> subreclist = new ArrayList<Subrecord>();
|
||||
|
@ -63,6 +66,7 @@ public class OmfFixupRecord extends OmfRecord {
|
|||
return subrecs;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static class Subrecord {
|
||||
private byte first;
|
||||
private byte hiFixup;
|
||||
|
@ -78,7 +82,7 @@ public class OmfFixupRecord extends OmfRecord {
|
|||
* @param reader The input file
|
||||
* @param hasBigFields Is this 16 or 32 bit values
|
||||
* @return The read subrecord
|
||||
* @throws IOException
|
||||
* @throws IOException if there was an IO-related error
|
||||
*/
|
||||
public static Subrecord readSubrecord(BinaryReader reader, boolean hasBigFields)
|
||||
throws IOException {
|
||||
|
@ -89,7 +93,7 @@ public class OmfFixupRecord extends OmfRecord {
|
|||
if (rec.isThreadSubrecord()) {
|
||||
method = rec.getThreadMethod();
|
||||
if (method < 4) {
|
||||
rec.index = readIndex(reader);
|
||||
rec.index = OmfUtils.readIndex(reader);
|
||||
}
|
||||
return rec;
|
||||
}
|
||||
|
@ -99,13 +103,13 @@ public class OmfFixupRecord extends OmfRecord {
|
|||
rec.fixData = reader.readNextByte();
|
||||
method = rec.getFrameMethod();
|
||||
if (!rec.isFrameThread() && method < 3) { // F=0 (explicit frame method (and datum))
|
||||
rec.frameDatum = readIndex(reader);
|
||||
rec.frameDatum = OmfUtils.readIndex(reader);
|
||||
}
|
||||
if (!rec.isTargetThread()) { // T=0 (explicit target)
|
||||
rec.targetDatum = readIndex(reader);
|
||||
rec.targetDatum = OmfUtils.readIndex(reader);
|
||||
}
|
||||
if ((rec.fixData & 0x04) == 0) { // P=0
|
||||
rec.targetDisplacement = readInt2Or4(reader, hasBigFields);
|
||||
rec.targetDisplacement = OmfUtils.readInt2Or4(reader, hasBigFields);
|
||||
}
|
||||
return rec;
|
||||
}
|
||||
|
@ -190,4 +194,9 @@ public class OmfFixupRecord extends OmfRecord {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
return OmfUtils.toOmfRecordDataType(this, OmfRecordTypes.getName(recordType));
|
||||
}
|
||||
|
||||
}
|
|
@ -13,16 +13,19 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.omf;
|
||||
package ghidra.app.util.bin.format.omf.omf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.omf.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public class OmfGroupRecord extends OmfRecord {
|
||||
private OmfIndex groupNameIndex;
|
||||
|
@ -33,7 +36,7 @@ public class OmfGroupRecord extends OmfRecord {
|
|||
public OmfGroupRecord(BinaryReader reader) throws IOException {
|
||||
readRecordHeader(reader);
|
||||
long max = reader.getPointerIndex() + getRecordLength() - 1;
|
||||
groupNameIndex = OmfRecord.readIndex(reader);
|
||||
groupNameIndex = OmfUtils.readIndex(reader);
|
||||
ArrayList<GroupSubrecord> grouplist = new ArrayList<GroupSubrecord>();
|
||||
while (reader.getPointerIndex() < max) {
|
||||
GroupSubrecord subrec = GroupSubrecord.read(reader);
|
||||
|
@ -98,8 +101,13 @@ public class OmfGroupRecord extends OmfRecord {
|
|||
public static GroupSubrecord read(BinaryReader reader) throws IOException {
|
||||
GroupSubrecord subrec = new GroupSubrecord();
|
||||
subrec.componentType = reader.readNextByte();
|
||||
subrec.segmentIndex = OmfRecord.readIndex(reader);
|
||||
subrec.segmentIndex = OmfUtils.readIndex(reader);
|
||||
return subrec;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
return OmfUtils.toOmfRecordDataType(this, OmfRecordTypes.getName(recordType));
|
||||
}
|
||||
}
|
|
@ -13,12 +13,16 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.omf;
|
||||
package ghidra.app.util.bin.format.omf.omf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.omf.Omf2or4;
|
||||
import ghidra.app.util.bin.format.omf.OmfUtils;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public class OmfIteratedData extends OmfData {
|
||||
|
||||
|
@ -29,8 +33,8 @@ public class OmfIteratedData extends OmfData {
|
|||
readRecordHeader(reader);
|
||||
long max = reader.getPointerIndex() + getRecordLength() - 1;
|
||||
boolean hasBigFields = hasBigFields();
|
||||
segmentIndex = OmfRecord.readIndex(reader);
|
||||
dataOffset = OmfRecord.readInt2Or4(reader, hasBigFields);
|
||||
segmentIndex = OmfUtils.readIndex(reader);
|
||||
dataOffset = OmfUtils.readInt2Or4(reader, hasBigFields);
|
||||
ArrayList<DataBlock> blocklist = new ArrayList<DataBlock>();
|
||||
while (reader.getPointerIndex() < max) {
|
||||
DataBlock block = DataBlock.read(reader, hasBigFields);
|
||||
|
@ -85,7 +89,7 @@ public class OmfIteratedData extends OmfData {
|
|||
|
||||
public static DataBlock read(BinaryReader reader, boolean hasBigFields) throws IOException {
|
||||
DataBlock subblock = new DataBlock();
|
||||
subblock.repeatCount = OmfRecord.readInt2Or4(reader, hasBigFields);
|
||||
subblock.repeatCount = OmfUtils.readInt2Or4(reader, hasBigFields);
|
||||
subblock.blockCount = reader.readNextUnsignedShort();
|
||||
if (subblock.blockCount == 0) {
|
||||
int size = reader.readNextByte() & 0xff;
|
||||
|
@ -163,4 +167,9 @@ public class OmfIteratedData extends OmfData {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
return OmfUtils.toOmfRecordDataType(this, OmfRecordTypes.getName(recordType));
|
||||
}
|
||||
}
|
|
@ -13,14 +13,18 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.omf;
|
||||
package ghidra.app.util.bin.format.omf.omf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.omf.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class OmfLibraryRecord extends OmfRecord {
|
||||
private int pageSize; // All archive members must start on a page boundary of this size
|
||||
private long dictionaryOffset;
|
||||
|
@ -118,4 +122,9 @@ public class OmfLibraryRecord extends OmfRecord {
|
|||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
return OmfUtils.toOmfRecordDataType(this, OmfRecordTypes.getName(recordType));
|
||||
}
|
||||
}
|
|
@ -13,11 +13,15 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.omf;
|
||||
package ghidra.app.util.bin.format.omf.omf;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.omf.OmfRecord;
|
||||
import ghidra.app.util.bin.format.omf.OmfUtils;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public class OmfModuleEnd extends OmfRecord {
|
||||
//private byte moduleType;
|
||||
|
@ -46,4 +50,9 @@ public class OmfModuleEnd extends OmfRecord {
|
|||
return ((moduleType & 0x40) != 0);
|
||||
}
|
||||
*/
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
return OmfUtils.toOmfRecordDataType(this, OmfRecordTypes.getName(recordType));
|
||||
}
|
||||
}
|
|
@ -13,13 +13,14 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.omf;
|
||||
package ghidra.app.util.bin.format.omf.omf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.omf.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
|
@ -30,7 +31,7 @@ public class OmfNamesRecord extends OmfRecord {
|
|||
readRecordHeader(reader);
|
||||
long max = reader.getPointerIndex() + getRecordLength() - 1;
|
||||
while (reader.getPointerIndex() < max) {
|
||||
names.add(OmfRecord.readString(reader));
|
||||
names.add(OmfUtils.readString(reader));
|
||||
}
|
||||
readCheckSumByte(reader);
|
||||
}
|
||||
|
@ -41,7 +42,7 @@ public class OmfNamesRecord extends OmfRecord {
|
|||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType(getRecordName(getRecordType()), 0);
|
||||
StructureDataType struct = new StructureDataType(OmfRecordTypes.getName(recordType), 0);
|
||||
struct.add(BYTE, "type", null);
|
||||
struct.add(WORD, "length", null);
|
||||
for (OmfString name : names) {
|
||||
|
@ -49,7 +50,7 @@ public class OmfNamesRecord extends OmfRecord {
|
|||
}
|
||||
struct.add(BYTE, "checksum", null);
|
||||
|
||||
struct.setCategoryPath(new CategoryPath(OmfRecord.CATEGORY_PATH));
|
||||
struct.setCategoryPath(new CategoryPath(OmfUtils.CATEGORY_PATH));
|
||||
return struct;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.omf.omf;
|
||||
|
||||
import static ghidra.app.util.bin.format.omf.omf.OmfRecordTypes.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.omf.*;
|
||||
|
||||
public class OmfRecordFactory {
|
||||
|
||||
public static OmfRecord readRecord(BinaryReader reader) throws IOException, OmfException {
|
||||
int type = Byte.toUnsignedInt(reader.peekNextByte());
|
||||
return switch (type & 0xfffffffe) { // mask off the least significant bit (16/32 bit flag)
|
||||
case THEADR:
|
||||
case LHEADR:
|
||||
yield new OmfFileHeader(reader);
|
||||
case COMENT:
|
||||
yield new OmfCommentRecord(reader);
|
||||
case MODEND:
|
||||
yield new OmfModuleEnd(reader);
|
||||
case EXTDEF:
|
||||
yield new OmfExternalSymbol(reader, false);
|
||||
case PUBDEF:
|
||||
yield new OmfSymbolRecord(reader, false);
|
||||
case LNAMES:
|
||||
yield new OmfNamesRecord(reader);
|
||||
case SEGDEF:
|
||||
yield new OmfSegmentHeader(reader);
|
||||
case GRPDEF:
|
||||
yield new OmfGroupRecord(reader);
|
||||
case FIXUPP:
|
||||
yield new OmfFixupRecord(reader);
|
||||
case LEDATA:
|
||||
yield new OmfEnumeratedData(reader);
|
||||
case LIDATA:
|
||||
yield new OmfIteratedData(reader);
|
||||
case COMDEF:
|
||||
yield new OmfComdefRecord(reader, false);
|
||||
case LEXTDEF:
|
||||
yield new OmfExternalSymbol(reader, true);
|
||||
case LPUBDEF:
|
||||
yield new OmfSymbolRecord(reader, true);
|
||||
case LCOMDEF:
|
||||
yield new OmfComdefRecord(reader, true);
|
||||
case CEXTDEF:
|
||||
yield new OmfComdatExternalSymbol(reader);
|
||||
case RHEADR:
|
||||
case REGINT:
|
||||
case REDATA:
|
||||
case RIDATA:
|
||||
case OVLDEF:
|
||||
case ENDREC:
|
||||
case BLKDEF:
|
||||
case BLKEND:
|
||||
case DEBSYM:
|
||||
case LINNUM:
|
||||
case PEDATA:
|
||||
case PIDATA:
|
||||
case LIBHED:
|
||||
case LIBNAM:
|
||||
case LIBLOC:
|
||||
case LIBDIC:
|
||||
yield new OmfObsoleteRecord(reader);
|
||||
case LOCSYM:
|
||||
case TYPDEF:
|
||||
case COMDAT:
|
||||
case LINSYM:
|
||||
case ALIAS:
|
||||
case BAKPAT:
|
||||
case NBKPAT:
|
||||
case LLNAMES:
|
||||
case VERNUM:
|
||||
case VENDEXT:
|
||||
yield new OmfUnsupportedRecord(reader, OmfRecordTypes.class);
|
||||
default:
|
||||
yield new OmfUnknownRecord(reader);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.omf.omf;
|
||||
|
||||
import ghidra.app.util.bin.format.omf.OmfUtils;
|
||||
|
||||
public class OmfRecordTypes {
|
||||
|
||||
public final static int RHEADR = 0x6E; // Obsolete
|
||||
public final static int REGINT = 0x70; // Obsolete
|
||||
public final static int REDATA = 0x72; // Obsolete
|
||||
public final static int RIDATA = 0x74; // Obsolete
|
||||
public final static int OVLDEF = 0x76; // Obsolete
|
||||
public final static int ENDREC = 0x78; // Obsolete
|
||||
public final static int BLKDEF = 0x7A; // Obsolete
|
||||
public final static int BLKEND = 0x7C; // Obsolete
|
||||
public final static int DEBSYM = 0x7E; // Obsolete
|
||||
public final static int THEADR = 0x80;
|
||||
public final static int LHEADR = 0x82;
|
||||
public final static int PEDATA = 0x84; // Obsolete
|
||||
public final static int PIDATA = 0x86; // Obsolete
|
||||
public final static int COMENT = 0x88;
|
||||
public final static int MODEND = 0x8A;
|
||||
public final static int EXTDEF = 0x8C;
|
||||
public final static int TYPDEF = 0x8E; // Obsolete
|
||||
public final static int PUBDEF = 0x90;
|
||||
public final static int LOCSYM = 0x92; // Obsolete
|
||||
public final static int LINNUM = 0x94;
|
||||
public final static int LNAMES = 0x96;
|
||||
public final static int SEGDEF = 0x98;
|
||||
public final static int GRPDEF = 0x9A;
|
||||
public final static int FIXUPP = 0x9C;
|
||||
public final static int LEDATA = 0xA0;
|
||||
public final static int LIDATA = 0xA2;
|
||||
public final static int LIBHED = 0xA4; // Obsolete
|
||||
public final static int LIBNAM = 0xA6; // Obsolete
|
||||
public final static int LIBLOC = 0xA8; // Obsolete
|
||||
public final static int LIBDIC = 0xAA; // Obsolete
|
||||
public final static int COMDEF = 0xB0;
|
||||
public final static int BAKPAT = 0xB2;
|
||||
public final static int LEXTDEF = 0xB4;
|
||||
public final static int LPUBDEF = 0xB6;
|
||||
public final static int LCOMDEF = 0xB8;
|
||||
public final static int CEXTDEF = 0xBC;
|
||||
public final static int COMDAT = 0xC2;
|
||||
public final static int LINSYM = 0xC4;
|
||||
public final static int ALIAS = 0xC6;
|
||||
public final static int NBKPAT = 0xC8;
|
||||
public final static int LLNAMES = 0xCA;
|
||||
public final static int VERNUM = 0xCC;
|
||||
public final static int VENDEXT = 0xCE;
|
||||
public final static int START = 0xF0;
|
||||
public final static int END = 0xF1;
|
||||
|
||||
/**
|
||||
* Gets the name of the given record type
|
||||
*
|
||||
* @param type The record type
|
||||
* @return The name of the given record type
|
||||
*/
|
||||
public final static String getName(int type) {
|
||||
return OmfUtils.getRecordName(type, OmfRecordTypes.class);
|
||||
}
|
||||
}
|
|
@ -13,13 +13,14 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.omf;
|
||||
package ghidra.app.util.bin.format.omf.omf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.omf.*;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.app.util.opinion.OmfLoader;
|
||||
import ghidra.program.model.address.Address;
|
||||
|
@ -91,14 +92,14 @@ public class OmfSegmentHeader extends OmfRecord {
|
|||
offset = reader.readNextByte() & 0xff;
|
||||
vma = (long) frameNumber + offset;
|
||||
}
|
||||
segmentLength = OmfRecord.readInt2Or4(reader, hasBigFields);
|
||||
segmentNameIndex = OmfRecord.readIndex(reader);
|
||||
classNameIndex = OmfRecord.readIndex(reader);
|
||||
overlayNameIndex = OmfRecord.readIndex(reader);
|
||||
segmentLength = OmfUtils.readInt2Or4(reader, hasBigFields);
|
||||
segmentNameIndex = OmfUtils.readIndex(reader);
|
||||
classNameIndex = OmfUtils.readIndex(reader);
|
||||
overlayNameIndex = OmfUtils.readIndex(reader);
|
||||
readCheckSumByte(reader);
|
||||
int B = (segAttr >> 1) & 1;
|
||||
if (B == 1) { // Ignore the segmentLength field
|
||||
if (getRecordType() == OmfRecord.SEGDEF) {
|
||||
if (getRecordType() == OmfRecordTypes.SEGDEF) {
|
||||
segmentLength = new Omf2or4(segmentLength.length(), 0x10000L); // Exactly 64K segment
|
||||
}
|
||||
else {
|
||||
|
@ -458,7 +459,7 @@ public class OmfSegmentHeader extends OmfRecord {
|
|||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType(getRecordName(getRecordType()), 0);
|
||||
StructureDataType struct = new StructureDataType(OmfRecordTypes.getName(recordType), 0);
|
||||
struct.add(BYTE, "type", null);
|
||||
struct.add(WORD, "length", null);
|
||||
struct.add(BYTE, "segment_attr", null);
|
||||
|
@ -473,7 +474,7 @@ public class OmfSegmentHeader extends OmfRecord {
|
|||
struct.add(overlayNameIndex.toDataType(), "overlay_name_index", null);
|
||||
struct.add(BYTE, "checksum", null);
|
||||
|
||||
struct.setCategoryPath(new CategoryPath(OmfRecord.CATEGORY_PATH));
|
||||
struct.setCategoryPath(new CategoryPath(OmfUtils.CATEGORY_PATH));
|
||||
return struct;
|
||||
}
|
||||
}
|
|
@ -13,12 +13,13 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.omf;
|
||||
package ghidra.app.util.bin.format.omf.omf;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class OmfSymbol {
|
||||
private String symbolName;
|
||||
private int typeIndex;
|
|
@ -13,13 +13,14 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.omf;
|
||||
package ghidra.app.util.bin.format.omf.omf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.format.omf.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
|
@ -38,17 +39,17 @@ public class OmfSymbolRecord extends OmfRecord {
|
|||
readRecordHeader(reader);
|
||||
long max = reader.getPointerIndex() + getRecordLength() - 1;
|
||||
boolean hasBigFields = hasBigFields();
|
||||
baseGroupIndex = OmfRecord.readIndex(reader);
|
||||
baseSegmentIndex = OmfRecord.readIndex(reader);
|
||||
baseGroupIndex = OmfUtils.readIndex(reader);
|
||||
baseSegmentIndex = OmfUtils.readIndex(reader);
|
||||
if (baseSegmentIndex.value() == 0) {
|
||||
baseFrame = reader.readNextUnsignedShort();
|
||||
}
|
||||
|
||||
ArrayList<OmfSymbol> symbollist = new ArrayList<OmfSymbol>();
|
||||
while (reader.getPointerIndex() < max) {
|
||||
OmfString name = OmfRecord.readString(reader);
|
||||
Omf2or4 offset = OmfRecord.readInt2Or4(reader, hasBigFields);
|
||||
OmfIndex type = OmfRecord.readIndex(reader);
|
||||
OmfString name = OmfUtils.readString(reader);
|
||||
Omf2or4 offset = OmfUtils.readInt2Or4(reader, hasBigFields);
|
||||
OmfIndex type = OmfUtils.readIndex(reader);
|
||||
OmfSymbol subrec = new OmfSymbol(name.str(), type.value(), offset.value(), 0, 0);
|
||||
symbollist.add(subrec);
|
||||
refs.add(new Reference(name, offset, type));
|
||||
|
@ -88,7 +89,7 @@ public class OmfSymbolRecord extends OmfRecord {
|
|||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct = new StructureDataType(getRecordName(getRecordType()), 0);
|
||||
StructureDataType struct = new StructureDataType(OmfRecordTypes.getName(recordType), 0);
|
||||
struct.add(BYTE, "type", null);
|
||||
struct.add(WORD, "length", null);
|
||||
struct.add(baseGroupIndex.toDataType(), "base_group_index", null);
|
||||
|
@ -103,7 +104,7 @@ public class OmfSymbolRecord extends OmfRecord {
|
|||
}
|
||||
struct.add(BYTE, "checksum", null);
|
||||
|
||||
struct.setCategoryPath(new CategoryPath(OmfRecord.CATEGORY_PATH));
|
||||
struct.setCategoryPath(new CategoryPath(OmfUtils.CATEGORY_PATH));
|
||||
return struct;
|
||||
}
|
||||
|
|
@ -24,7 +24,8 @@ import ghidra.app.util.Option;
|
|||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.format.omf.*;
|
||||
import ghidra.app.util.bin.format.omf.OmfFixupRecord.Subrecord;
|
||||
import ghidra.app.util.bin.format.omf.omf.*;
|
||||
import ghidra.app.util.bin.format.omf.omf.OmfFixupRecord.Subrecord;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.program.database.function.OverlappingFunctionException;
|
||||
import ghidra.program.database.mem.FileBytes;
|
||||
|
|
|
@ -21,8 +21,8 @@ import java.io.IOException;
|
|||
import java.util.ArrayList;
|
||||
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.app.util.bin.format.omf.OmfFileHeader;
|
||||
import ghidra.app.util.bin.format.omf.OmfLibraryRecord;
|
||||
import ghidra.app.util.bin.format.omf.omf.OmfFileHeader;
|
||||
import ghidra.app.util.bin.format.omf.omf.OmfLibraryRecord;
|
||||
import ghidra.formats.gfilesystem.*;
|
||||
import ghidra.formats.gfilesystem.annotations.FileSystemInfo;
|
||||
import ghidra.formats.gfilesystem.fileinfo.FileAttributes;
|
||||
|
|
|
@ -19,8 +19,8 @@ import java.io.IOException;
|
|||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.format.omf.OmfFileHeader;
|
||||
import ghidra.app.util.bin.format.omf.OmfLibraryRecord;
|
||||
import ghidra.app.util.bin.format.omf.omf.OmfFileHeader;
|
||||
import ghidra.app.util.bin.format.omf.omf.OmfLibraryRecord;
|
||||
import ghidra.app.util.opinion.OmfLoader;
|
||||
import ghidra.formats.gfilesystem.FSRLRoot;
|
||||
import ghidra.formats.gfilesystem.FileSystemService;
|
||||
|
|
|
@ -14,3 +14,7 @@ data/languages/6x09_pull.sinc||GHIDRA||||END|
|
|||
data/languages/6x09_push.sinc||GHIDRA||||END|
|
||||
data/languages/H6309.slaspec||GHIDRA||||END|
|
||||
data/manuals/6809.idx||GHIDRA||||END|
|
||||
data/languages/mc6800.cspec||GHIDRA||||END|
|
||||
data/languages/mc6800.ldefs||GHIDRA||||END|
|
||||
data/languages/mc6800.pspec||GHIDRA||||END|
|
||||
data/languages/mc6800.slaspec||GHIDRA||||END|
|
||||
|
|
31
Ghidra/Processors/MC6800/data/languages/mc6800.cspec
Normal file
31
Ghidra/Processors/MC6800/data/languages/mc6800.cspec
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<compiler_spec>
|
||||
<global>
|
||||
<range space="RAM"/>
|
||||
</global>
|
||||
<stackpointer register="S" space="RAM" growth="negative"/>
|
||||
<default_proto>
|
||||
<prototype name="__stdcall" extrapop="2" stackshift="2">
|
||||
<input>
|
||||
<pentry minsize="1" maxsize="1">
|
||||
<register name="A"/>
|
||||
</pentry>
|
||||
<pentry minsize="1" maxsize="1">
|
||||
<register name="B"/>
|
||||
</pentry>
|
||||
<pentry minsize="1" maxsize="2">
|
||||
<register name="X"/>
|
||||
</pentry>
|
||||
</input>
|
||||
<output>
|
||||
<pentry minsize="1" maxsize="1">
|
||||
<register name="A"/>
|
||||
</pentry>
|
||||
</output>
|
||||
<unaffected>
|
||||
<register name="S"/>
|
||||
</unaffected>
|
||||
</prototype>
|
||||
</default_proto>
|
||||
</compiler_spec>
|
22
Ghidra/Processors/MC6800/data/languages/mc6800.ldefs
Normal file
22
Ghidra/Processors/MC6800/data/languages/mc6800.ldefs
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
TODO(siggi): It might be nice to have a separate processor definition for
|
||||
the MC6802 as it has built-in RAM.
|
||||
-->
|
||||
<language_definitions>
|
||||
<language processor="MC6800"
|
||||
endian="big"
|
||||
size="16"
|
||||
variant="default"
|
||||
version="1.0"
|
||||
slafile="mc6800.sla"
|
||||
processorspec="mc6800.pspec"
|
||||
id="MC6800:BE:16:default">
|
||||
<description>MC6800 Microprocessor</description>
|
||||
<compiler name="default" spec="mc6800.cspec" id="default"/>
|
||||
<external_name tool="IDA-PRO" name="MC6800"/>
|
||||
<external_name tool="IDA-PRO" name="MC6802"/>
|
||||
<external_name tool="IDA-PRO" name="MC6808"/>
|
||||
</language>
|
||||
</language_definitions>
|
11
Ghidra/Processors/MC6800/data/languages/mc6800.pspec
Normal file
11
Ghidra/Processors/MC6800/data/languages/mc6800.pspec
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<processor_spec>
|
||||
<programcounter register="PC"/>
|
||||
<default_symbols>
|
||||
<symbol name="IRQ_VECTOR" address="0xFFF8" entry="true" type="code_ptr"/>
|
||||
<symbol name="SWI_VECTOR" address="0xFFFA" entry="true" type="code_ptr"/>
|
||||
<symbol name="NMI_VECTOR" address="0xFFFC" entry="true" type="code_ptr"/>
|
||||
<symbol name="RST_VECTOR" address="0xFFFE" entry="true" type="code_ptr"/>
|
||||
</default_symbols>
|
||||
</processor_spec>
|
927
Ghidra/Processors/MC6800/data/languages/mc6800.slaspec
Normal file
927
Ghidra/Processors/MC6800/data/languages/mc6800.slaspec
Normal file
|
@ -0,0 +1,927 @@
|
|||
# sleigh specification file for Motorola 6800/6802/6808
|
||||
|
||||
define endian=big;
|
||||
define alignment=1;
|
||||
|
||||
@define IRQ_VECTOR "0xFFF8"
|
||||
@define SWI_VECTOR "0xFFFA"
|
||||
@define NMI_VECTOR "0xFFFC"
|
||||
@define RST_VECTOR "0xFFFE"
|
||||
|
||||
define space RAM type=ram_space size=2 default;
|
||||
define space register type=register_space size=1;
|
||||
|
||||
# 8-bit registers A, B
|
||||
define register offset=0 size=1 [ A B ];
|
||||
|
||||
# 8-bit condition code register
|
||||
define register offset=8 size=1 [ CC ];
|
||||
# 16-bit registers:
|
||||
# PC: Program counter
|
||||
# S: Stack pointer
|
||||
# X: index register
|
||||
define register offset=16 size=2 [ PC X S ];
|
||||
|
||||
# define status bits: (See also 8051/z80).
|
||||
@define C "CC[0,1]" # C: Carry (or borrow) flag
|
||||
@define V "CC[1,1]" # V: Overflow flag
|
||||
@define Z "CC[2,1]" # Z: Zero result
|
||||
@define N "CC[3,1]" # N: Negative result (twos complement)
|
||||
@define I "CC[4,1]" # I: IRQ interrupt masked
|
||||
@define H "CC[5,1]" # H: Half carry flag
|
||||
|
||||
define token opbyte (8)
|
||||
op = (0,7)
|
||||
addrMode = (4,5)
|
||||
acc_4 = (4,4)
|
||||
;
|
||||
|
||||
define token data8 (8)
|
||||
imm8 = (0,7)
|
||||
simm8 = (0,7) signed
|
||||
;
|
||||
|
||||
define token data (16)
|
||||
imm16 = (0,15)
|
||||
;
|
||||
|
||||
attach variables acc_4 [ A B ];
|
||||
|
||||
################################################################
|
||||
# Constructors
|
||||
################################################################
|
||||
|
||||
REL: addr is simm8 [ addr = inst_next + simm8; ] { export *:2 addr; }
|
||||
|
||||
# 1-byte operand, immediate/direct/indexed/extended addressing mode
|
||||
OP1: "#"imm8 is addrMode=0; imm8
|
||||
{
|
||||
# For some reason this needs explicit sizing, or the p-code
|
||||
# ends up picking up a zero value for all #imm8 operands.
|
||||
local tmp:1 = imm8;
|
||||
export tmp;
|
||||
}
|
||||
OP1: imm8 is addrMode=1; imm8
|
||||
{
|
||||
export *:1 imm8;
|
||||
}
|
||||
OP1: imm8,X is addrMode=2 & X; imm8
|
||||
{
|
||||
local tmp:2 = imm8 + X;
|
||||
export *:1 tmp;
|
||||
}
|
||||
OP1: imm16 is addrMode=3; imm16
|
||||
{
|
||||
export *:1 imm16;
|
||||
}
|
||||
|
||||
# 2-byte operand, direct/indexed/extended addressing mode
|
||||
OP2: "#"imm16 is addrMode=0; imm16
|
||||
{
|
||||
local tmp:2 = imm16;
|
||||
export tmp;
|
||||
}
|
||||
OP2: imm8 is addrMode=1; imm8
|
||||
{
|
||||
export *:2 imm8;
|
||||
}
|
||||
OP2: imm8,X is addrMode=2 & X; imm8
|
||||
{
|
||||
local tmp:2 = X + imm8;
|
||||
export *:2 tmp;
|
||||
}
|
||||
OP2: imm16 is addrMode=3; imm16
|
||||
{
|
||||
export *:2 imm16;
|
||||
}
|
||||
|
||||
# 2-byte EA operand for JMP/JSR
|
||||
EA2: imm8,X is addrMode=2 & X; imm8
|
||||
{
|
||||
local tmp:2 = X + imm8;
|
||||
export tmp;
|
||||
}
|
||||
EA2: imm16 is addrMode=3; imm16
|
||||
{
|
||||
local tmp:2 = imm16;
|
||||
export tmp;
|
||||
}
|
||||
|
||||
|
||||
################################################################
|
||||
# Macros
|
||||
################################################################
|
||||
|
||||
macro setNZFlags(result)
|
||||
{
|
||||
$(Z) = (result == 0);
|
||||
$(N) = (result s< 0);
|
||||
}
|
||||
|
||||
macro setHFlag(reg, op)
|
||||
{
|
||||
local mask = 0x0F; # Low nibble mask
|
||||
|
||||
$(H) = (((reg & mask) + (op & mask)) >> 4) & 1;
|
||||
}
|
||||
|
||||
# Negate twos complement value in op.
|
||||
# P-code INT_2COMP.
|
||||
macro negate(op)
|
||||
{
|
||||
op = -op;
|
||||
$(V) = (op == 0x80);
|
||||
$(C) = (op != 0);
|
||||
setNZFlags(op);
|
||||
}
|
||||
|
||||
# Logical complement of op. (0 => 1; 1 => 0)
|
||||
# P-code INT_NEGATE.
|
||||
macro complement(op)
|
||||
{
|
||||
$(V) = 0;
|
||||
$(C) = 1;
|
||||
op = ~op;
|
||||
setNZFlags(op);
|
||||
}
|
||||
|
||||
macro logicalShiftRight(op)
|
||||
{
|
||||
$(C) = op & 1;
|
||||
op = op >> 1;
|
||||
$(Z) = (op == 0);
|
||||
$(N) = 0;
|
||||
}
|
||||
|
||||
macro rotateRightWithCarry(op)
|
||||
{
|
||||
local carryOut = $(C) << 7;
|
||||
$(C) = op & 1;
|
||||
op = (op s>> 1) | carryOut;
|
||||
setNZFlags(op);
|
||||
}
|
||||
|
||||
macro rotateLeftWithCarry(op)
|
||||
{
|
||||
local carryIn = $(C);
|
||||
$(C) = op >> 7;
|
||||
op = (op << 1) | carryIn;
|
||||
setNZFlags(op);
|
||||
}
|
||||
|
||||
# Signed shift right.
|
||||
# P-code INT_SRIGHT.
|
||||
macro arithmeticShiftRight(op)
|
||||
{
|
||||
$(C) = op & 1;
|
||||
op = (op s>> 1);
|
||||
setNZFlags(op);
|
||||
}
|
||||
|
||||
macro logicalShiftLeft(op)
|
||||
{
|
||||
$(C) = (op >> 7);
|
||||
op = op << 1;
|
||||
$(Z) = (op == 0);
|
||||
$(N) = (op >> 7);
|
||||
}
|
||||
|
||||
macro increment(op)
|
||||
{
|
||||
$(V) = (op == 0x7F);
|
||||
op = op + 1;
|
||||
setNZFlags(op);
|
||||
}
|
||||
|
||||
macro decrement(op)
|
||||
{
|
||||
$(V) = (op == 0x80);
|
||||
op = op - 1;
|
||||
setNZFlags(op);
|
||||
}
|
||||
|
||||
macro test(op)
|
||||
{
|
||||
$(V) = 0;
|
||||
setNZFlags(op);
|
||||
}
|
||||
|
||||
macro clear(op)
|
||||
{
|
||||
$(V) = 0;
|
||||
op = 0;
|
||||
$(Z) = 1;
|
||||
$(N) = 0;
|
||||
}
|
||||
|
||||
macro addition(reg, op)
|
||||
{
|
||||
$(C) = carry(reg, op);
|
||||
$(V) = scarry(reg, op);
|
||||
|
||||
reg = reg + op;
|
||||
|
||||
setNZFlags(reg);
|
||||
}
|
||||
|
||||
macro additionWithCarry(reg, op)
|
||||
{
|
||||
local carryIn = $(C);
|
||||
local mask = 0x0F; # Low nibble mask
|
||||
local tmpResult = reg + op;
|
||||
|
||||
$(H) = (((reg & mask) + (op & mask) + carryIn) >> 4) & 1;
|
||||
$(C) = carry(reg, op) || carry(tmpResult, carryIn);
|
||||
$(V) = scarry(reg, op) ^^ scarry(tmpResult, carryIn);
|
||||
|
||||
reg = tmpResult + carryIn;
|
||||
|
||||
setNZFlags(reg);
|
||||
}
|
||||
|
||||
macro subtraction(reg, op)
|
||||
{
|
||||
$(V) = sborrow(reg, op);
|
||||
reg = reg - op;
|
||||
setNZFlags(reg);
|
||||
$(C) = (reg < op);
|
||||
}
|
||||
|
||||
macro subtractionWithCarry(reg, op)
|
||||
{
|
||||
local carryIn = $(C);
|
||||
local tmpResult = reg - op;
|
||||
|
||||
$(C) = (reg < op) || (tmpResult < carryIn);
|
||||
$(V) = sborrow(reg, op) ^^ sborrow(tmpResult, carryIn);
|
||||
|
||||
reg = tmpResult - carryIn;
|
||||
|
||||
setNZFlags(reg);
|
||||
}
|
||||
|
||||
macro compare(reg, op)
|
||||
{
|
||||
$(V) = sborrow(reg, op);
|
||||
local tmp = reg - op;
|
||||
setNZFlags(tmp);
|
||||
$(C) = (tmp < op);
|
||||
}
|
||||
|
||||
macro logicalAnd(reg, op)
|
||||
{
|
||||
reg = reg & op;
|
||||
setNZFlags(reg);
|
||||
$(V) = 0;
|
||||
}
|
||||
|
||||
macro logicalOr(reg, op)
|
||||
{
|
||||
reg = reg | op;
|
||||
setNZFlags(reg);
|
||||
$(V) = 0;
|
||||
}
|
||||
|
||||
macro logicalExclusiveOr(reg, op)
|
||||
{
|
||||
reg = reg ^ op;
|
||||
setNZFlags(reg);
|
||||
$(V) = 0;
|
||||
}
|
||||
|
||||
macro bitTest(reg, op)
|
||||
{
|
||||
local tmp = reg & op;
|
||||
setNZFlags(tmp);
|
||||
$(V) = 0;
|
||||
}
|
||||
|
||||
macro loadRegister(reg, op)
|
||||
{
|
||||
reg = op;
|
||||
setNZFlags(reg);
|
||||
$(V) = 0;
|
||||
}
|
||||
|
||||
macro storeRegister(reg, op)
|
||||
{
|
||||
op = reg;
|
||||
setNZFlags(reg);
|
||||
$(V) = 0;
|
||||
}
|
||||
|
||||
# Push 1 byte operand op
|
||||
macro Push1(reg, op)
|
||||
{
|
||||
*:1 reg = op;
|
||||
reg = reg - 1;
|
||||
}
|
||||
|
||||
# Push 2 byte operand op
|
||||
macro Push2(reg, op)
|
||||
{
|
||||
reg = reg - 1;
|
||||
*:2 reg = op;
|
||||
reg = reg - 1;
|
||||
}
|
||||
|
||||
# Pull 1 byte operand op
|
||||
macro Pull1(reg, op)
|
||||
{
|
||||
reg = reg + 1;
|
||||
op = *:1 reg;
|
||||
}
|
||||
|
||||
# Pull 2 byte operand op
|
||||
macro Pull2(reg, op)
|
||||
{
|
||||
reg = reg + 1;
|
||||
op = *:2 reg;
|
||||
reg = reg + 1;
|
||||
}
|
||||
|
||||
macro PushEntireState()
|
||||
{
|
||||
local tmp:2 = inst_next;
|
||||
|
||||
Push2(S, tmp); # return PC address
|
||||
Push2(S, X);
|
||||
Push1(S, A);
|
||||
Push1(S, B);
|
||||
Push1(S, CC);
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Instructions
|
||||
################################################################
|
||||
|
||||
################################################################
|
||||
# Opcode 0x00 - 0x0F, misc operations
|
||||
################################################################
|
||||
|
||||
:NOP is op=0x01
|
||||
{
|
||||
# Intentional NOP.
|
||||
goto inst_next;
|
||||
}
|
||||
|
||||
:TAP is op=0x06
|
||||
{
|
||||
CC = A & 0x1F;
|
||||
}
|
||||
|
||||
:TPA is op=0x07
|
||||
{
|
||||
A = CC;
|
||||
}
|
||||
|
||||
:INX is op=0x08
|
||||
{
|
||||
X = X + 1;
|
||||
$(Z) = (X == 0);
|
||||
}
|
||||
|
||||
:DEX is op=0x09
|
||||
{
|
||||
X = X - 1;
|
||||
$(Z) = (X == 0);
|
||||
}
|
||||
|
||||
:CLV is op=0x0A
|
||||
{
|
||||
$(V) = 0;
|
||||
}
|
||||
|
||||
:SEV is op=0x0B
|
||||
{
|
||||
$(V) = 1;
|
||||
}
|
||||
|
||||
:CLC is op=0x0C
|
||||
{
|
||||
$(C) = 0;
|
||||
}
|
||||
|
||||
:SEC is op=0x0D
|
||||
{
|
||||
$(C) = 1;
|
||||
}
|
||||
|
||||
:CLI is op=0x0E
|
||||
{
|
||||
$(I) = 0;
|
||||
}
|
||||
|
||||
:SEI is op=0x0F
|
||||
{
|
||||
$(I) = 1;
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Opcode 0x40 - 0x4F, register A addressing
|
||||
# Opcode 0x50 - 0x5F, register B addressing
|
||||
# Opcode 0x60 - 0x6F, indexed addressing
|
||||
# Opcode 0x70 - 0x7F, extended addressing
|
||||
################################################################
|
||||
|
||||
:NEG^acc_4 is (op=0x40 | op=0x50) & acc_4
|
||||
{
|
||||
negate(acc_4);
|
||||
}
|
||||
|
||||
:NEG OP1 is (op=0x60 | op=0x70) ... & OP1
|
||||
{
|
||||
negate(OP1);
|
||||
}
|
||||
|
||||
:COM^acc_4 is (op=0x43 | op=0x53) & acc_4
|
||||
{
|
||||
complement(acc_4);
|
||||
}
|
||||
|
||||
:COM OP1 is (op=0x63 | op=0x73) ... & OP1
|
||||
{
|
||||
complement(OP1);
|
||||
}
|
||||
|
||||
:LSR^acc_4 is (op=0x44 | op=0x54) & acc_4
|
||||
{
|
||||
logicalShiftRight(acc_4);
|
||||
}
|
||||
|
||||
:LSR OP1 is (op=0x64 | op=0x74) ... & OP1
|
||||
{
|
||||
logicalShiftRight(OP1);
|
||||
}
|
||||
|
||||
:ROR^acc_4 is (op=0x46 | op=0x56) & acc_4
|
||||
{
|
||||
rotateRightWithCarry(acc_4);
|
||||
}
|
||||
|
||||
:ROR OP1 is (op=0x66 | op=0x76) ... & OP1
|
||||
{
|
||||
rotateRightWithCarry(OP1);
|
||||
}
|
||||
|
||||
:ASR^acc_4 is (op=0x47 | op=0x57) & acc_4
|
||||
{
|
||||
arithmeticShiftRight(acc_4);
|
||||
}
|
||||
|
||||
:ASR OP1 is (op=0x67 | op=0x77) ... & OP1
|
||||
{
|
||||
arithmeticShiftRight(OP1);
|
||||
}
|
||||
|
||||
:ASL^acc_4 is (op=0x48 | op=0x58) & acc_4
|
||||
{
|
||||
logicalShiftLeft(acc_4);
|
||||
}
|
||||
|
||||
:ASL OP1 is (op=0x68 | op=0x78) ... & OP1
|
||||
{
|
||||
logicalShiftLeft(OP1);
|
||||
}
|
||||
|
||||
:ROL^acc_4 is (op=0x49 | op=0x59) & acc_4
|
||||
{
|
||||
rotateLeftWithCarry(acc_4);
|
||||
}
|
||||
|
||||
:ROL OP1 is (op=0x69 | op=0x79) ... & OP1
|
||||
{
|
||||
rotateLeftWithCarry(OP1);
|
||||
}
|
||||
|
||||
:DEC^acc_4 is (op=0x4A | op=0x5A) & acc_4
|
||||
{
|
||||
decrement(acc_4);
|
||||
}
|
||||
|
||||
:DEC OP1 is (op=0x6A | op=0x7A) ... & OP1
|
||||
{
|
||||
decrement(OP1);
|
||||
}
|
||||
|
||||
:INC^acc_4 is (op=0x4C | op=0x5C) & acc_4
|
||||
{
|
||||
increment(acc_4);
|
||||
}
|
||||
|
||||
:INC OP1 is (op=0x6C | op=0x7C) ... & OP1
|
||||
{
|
||||
increment(OP1);
|
||||
}
|
||||
|
||||
:TST^acc_4 is (op=0x4D | op=0x5D) & acc_4
|
||||
{
|
||||
test(acc_4);
|
||||
}
|
||||
|
||||
:TST OP1 is (op=0x6D | op=0x7D) ... & OP1
|
||||
{
|
||||
test(OP1);
|
||||
}
|
||||
|
||||
:JMP EA2 is (op=0x6E | op=0x7E) ... & EA2
|
||||
{
|
||||
local target:2 = EA2;
|
||||
goto [target];
|
||||
}
|
||||
|
||||
:CLR^acc_4 is (op=0x4F | op=0x5F) & acc_4
|
||||
{
|
||||
clear(acc_4);
|
||||
}
|
||||
|
||||
:CLR OP1 is (op=0x6F | op=0x7F) ... & OP1
|
||||
{
|
||||
clear(OP1);
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Opcode 0x10 - 0x1F, misc. addressing
|
||||
################################################################
|
||||
|
||||
:SBA is op=0x10
|
||||
{
|
||||
subtraction(A, B);
|
||||
}
|
||||
|
||||
:CBA is op=0x11
|
||||
{
|
||||
compare(A, B);
|
||||
}
|
||||
|
||||
:TAB is op=0x16
|
||||
{
|
||||
loadRegister(B, A);
|
||||
}
|
||||
|
||||
:TBA is op=0x17
|
||||
{
|
||||
loadRegister(A, B);
|
||||
}
|
||||
|
||||
:DAA is op=0x19
|
||||
{
|
||||
local highA:1 = A >> 4;
|
||||
local lowA:1 = A & 0x0F;
|
||||
local cc1 = ($(C) == 1 | highA > 9 | (highA > 8) & (lowA > 9));
|
||||
local cc2 = ($(H) == 1 | lowA > 9);
|
||||
|
||||
if ( cc1 & cc2 )
|
||||
goto <case1>;
|
||||
if ( cc1 )
|
||||
goto <case2>;
|
||||
if ( cc2 )
|
||||
goto <case3>;
|
||||
goto <exitDAA>;
|
||||
|
||||
<case1>
|
||||
$(C) = carry(A, 0x66);
|
||||
A = A + 0x66;
|
||||
goto <exitDAA>;
|
||||
<case2>
|
||||
$(C) = carry(A, 0x60);
|
||||
A = A + 0x60;
|
||||
goto <exitDAA>;
|
||||
<case3>
|
||||
$(C) = carry(A, 0x06);
|
||||
A = A + 0x06;
|
||||
goto <exitDAA>;
|
||||
|
||||
<exitDAA>
|
||||
setNZFlags(A);
|
||||
}
|
||||
|
||||
:ABA is op=0x1B
|
||||
{
|
||||
addition(A, B);
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Opcode 0x20 - 0x2F, relative addressing
|
||||
################################################################
|
||||
|
||||
:BRA REL is op=0x20; REL
|
||||
{
|
||||
goto REL;
|
||||
}
|
||||
|
||||
:BHI REL is op=0x22; REL
|
||||
{
|
||||
local tmp = $(C) + $(Z);
|
||||
if (tmp == 0) goto REL;
|
||||
}
|
||||
|
||||
:BLS REL is op=0x23; REL
|
||||
{
|
||||
local tmp = $(C) + $(Z);
|
||||
if (tmp) goto REL;
|
||||
}
|
||||
|
||||
#:BHS REL is op=0x24; REL # See BCC
|
||||
|
||||
:BCC REL is op=0x24; REL
|
||||
{
|
||||
if ($(C) == 0) goto REL;
|
||||
}
|
||||
|
||||
#:BLO REL is op=0x25; REL # see BCS
|
||||
|
||||
:BCS REL is op=0x25; REL
|
||||
{
|
||||
if ($(C)) goto REL;
|
||||
}
|
||||
|
||||
:BNE REL is op=0x26; REL
|
||||
{
|
||||
if ($(Z) == 0) goto REL;
|
||||
}
|
||||
|
||||
:BEQ REL is op=0x27; REL
|
||||
{
|
||||
if ($(Z)) goto REL;
|
||||
}
|
||||
|
||||
:BVC REL is op=0x28; REL
|
||||
{
|
||||
if ($(V) == 0) goto REL;
|
||||
}
|
||||
|
||||
:BVS REL is op=0x29; REL
|
||||
{
|
||||
if ($(V)) goto REL;
|
||||
}
|
||||
|
||||
:BPL REL is op=0x2A; REL
|
||||
{
|
||||
if ($(N) == 0) goto REL;
|
||||
}
|
||||
|
||||
:BMI REL is op=0x2B; REL
|
||||
{
|
||||
if ($(N)) goto REL;
|
||||
}
|
||||
|
||||
:BGE REL is op=0x2C; REL
|
||||
{
|
||||
if ($(N) == $(V)) goto REL;
|
||||
}
|
||||
|
||||
:BLT REL is op=0x2D; REL
|
||||
{
|
||||
local tmp = $(C) ^ $(Z);
|
||||
if (tmp) goto REL;
|
||||
}
|
||||
|
||||
:BGT REL is op=0x2E; REL
|
||||
{
|
||||
if (($(N) == $(V)) & $(C)) goto REL;
|
||||
}
|
||||
|
||||
:BLE REL is op=0x2F; REL
|
||||
{
|
||||
local tmp = $(N) ^ $(V);
|
||||
if (tmp | $(Z)) goto REL;
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Opcode 0x30 - 0x3F, misc. addressing
|
||||
################################################################
|
||||
|
||||
:TSX is op=0x30
|
||||
{
|
||||
X = S + 1;
|
||||
}
|
||||
|
||||
:INS is op=0x31
|
||||
{
|
||||
S = S + 1;
|
||||
}
|
||||
|
||||
:PULA is op=0x32
|
||||
{
|
||||
Pull1(S, A);
|
||||
}
|
||||
|
||||
:PULB is op=0x33
|
||||
{
|
||||
Pull1(S, B);
|
||||
}
|
||||
|
||||
:DES is op=0x34
|
||||
{
|
||||
S = S - 1;
|
||||
}
|
||||
|
||||
:TXS is op=0x35
|
||||
{
|
||||
S = X - 1;
|
||||
}
|
||||
|
||||
:PSHA is op=0x36
|
||||
{
|
||||
Push1(S, A);
|
||||
}
|
||||
|
||||
:PSHB is op=0x37
|
||||
{
|
||||
Push1(S, B);
|
||||
}
|
||||
|
||||
:RTS is op=0x39
|
||||
{
|
||||
local addr:2;
|
||||
Pull2(S, addr);
|
||||
return [addr];
|
||||
}
|
||||
|
||||
:RTI is op=0x3B
|
||||
{
|
||||
local addr:2;
|
||||
Pull1(S, CC);
|
||||
Pull1(S, B);
|
||||
Pull1(S, A);
|
||||
Pull2(S, X);
|
||||
Pull2(S, addr);
|
||||
return [addr];
|
||||
}
|
||||
|
||||
:WAI is op=0x3E
|
||||
{
|
||||
PushEntireState();
|
||||
}
|
||||
|
||||
:SWI is op=0x3F
|
||||
{
|
||||
PushEntireState();
|
||||
$(I) = 1;
|
||||
tmp:2 = $(SWI_VECTOR);
|
||||
call[tmp];
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Opcode 0x80 - 0x8F, immediate addressing
|
||||
# Opcode 0x90 - 0x9F, direct addressing
|
||||
# Opcode 0xA0 - 0xAF, indexed addressing
|
||||
# Opcode 0xB0 - 0xBF, extended addressing
|
||||
# Opcode 0xC0 - 0xCF, immediate addressing
|
||||
# Opcode 0xD0 - 0xDF, direct addressing
|
||||
# Opcode 0xE0 - 0xEF, indexed addressing
|
||||
# Opcode 0xF0 - 0xFF, extended addressing
|
||||
################################################################
|
||||
|
||||
:SUBA OP1 is (op=0x80 | op=0x90 | op=0xA0 | op=0xB0) ... & OP1
|
||||
{
|
||||
subtraction(A, OP1);
|
||||
}
|
||||
|
||||
:SUBB OP1 is (op=0xC0 | op=0xD0 | op=0xE0 | op=0xF0) ... & OP1
|
||||
{
|
||||
subtraction(B, OP1);
|
||||
}
|
||||
|
||||
:CMPA OP1 is (op=0x81 | op=0x91 | op=0xA1 | op=0xB1) ... & OP1
|
||||
{
|
||||
compare(A, OP1);
|
||||
}
|
||||
|
||||
:CMPB OP1 is (op=0xC1 | op=0xD1 | op=0xE1 | op=0xF1) ... & OP1
|
||||
{
|
||||
compare(B, OP1);
|
||||
}
|
||||
|
||||
:SBCA OP1 is (op=0x82 | op=0x92 | op=0xA2 | op=0xB2) ... & OP1
|
||||
{
|
||||
subtractionWithCarry(A, OP1);
|
||||
}
|
||||
|
||||
:SBCB OP1 is (op=0xC2 | op=0xD2 | op=0xE2 | op=0xF2) ... & OP1
|
||||
{
|
||||
subtractionWithCarry(B, OP1);
|
||||
}
|
||||
|
||||
:ANDA OP1 is (op=0x84 | op=0x94 | op=0xA4 | op=0xB4) ... & OP1
|
||||
{
|
||||
logicalAnd(A, OP1);
|
||||
}
|
||||
|
||||
:ANDB OP1 is (op=0xC4 | op=0xD4 | op=0xE4 | op=0xF4) ... & OP1
|
||||
{
|
||||
logicalAnd(B, OP1);
|
||||
}
|
||||
|
||||
:BITA OP1 is (op=0x85 | op=0x95 | op=0xA5 | op=0xB5) ... & OP1
|
||||
{
|
||||
bitTest(A, OP1);
|
||||
}
|
||||
|
||||
:BITB OP1 is (op=0xC5 | op=0xD5 | op=0xE5 | op=0xF5) ... & OP1
|
||||
{
|
||||
bitTest(B, OP1);
|
||||
}
|
||||
|
||||
:LDAA OP1 is (op=0x86 | op=0x96 | op=0xA6 | op=0xB6) ... & OP1
|
||||
{
|
||||
loadRegister(A, OP1);
|
||||
}
|
||||
|
||||
:LDAB OP1 is (op=0xC6 | op=0xD6 | op=0xE6 | op=0xF6) ... & OP1
|
||||
{
|
||||
loadRegister(B, OP1);
|
||||
}
|
||||
|
||||
:STAA OP1 is (op=0x97 | op=0xA7 | op=0xB7) ... & OP1
|
||||
{
|
||||
storeRegister(A, OP1);
|
||||
}
|
||||
|
||||
:STAB OP1 is (op=0xD7 | op=0xE7 | op=0xF7) ... & OP1
|
||||
{
|
||||
storeRegister(B, OP1);
|
||||
}
|
||||
|
||||
:EORA OP1 is (op=0x88 | op=0x98 | op=0xA8 | op=0xB8) ... & OP1
|
||||
{
|
||||
logicalExclusiveOr(A, OP1);
|
||||
}
|
||||
|
||||
:EORB OP1 is (op=0xC8 | op=0xD8 | op=0xE8 | op=0xF8) ... & OP1
|
||||
{
|
||||
logicalExclusiveOr(B, OP1);
|
||||
}
|
||||
|
||||
:ADCA OP1 is (op=0x89 | op=0x99 | op=0xA9 | op=0xB9) ... & OP1
|
||||
{
|
||||
additionWithCarry(A, OP1);
|
||||
}
|
||||
|
||||
:ADCB OP1 is (op=0xC9 | op=0xD9 | op=0xE9 | op=0xF9) ... & OP1
|
||||
{
|
||||
additionWithCarry(B, OP1);
|
||||
}
|
||||
|
||||
:ORAA OP1 is (op=0x8A | op=0x9A | op=0xAA | op=0xBA) ... & OP1
|
||||
{
|
||||
logicalOr(A, OP1);
|
||||
}
|
||||
|
||||
:ORAB OP1 is (op=0xCA | op=0xDA | op=0xEA | op=0xFA) ... & OP1
|
||||
{
|
||||
logicalOr(B, OP1);
|
||||
}
|
||||
|
||||
:ADDA OP1 is (op=0x8B | op=0x9B | op=0xAB | op=0xBB) ... & OP1
|
||||
{
|
||||
setHFlag(A, OP1);
|
||||
addition(A, OP1);
|
||||
}
|
||||
|
||||
:ADDB OP1 is (op=0xCB | op=0xDB | op=0xEB | op=0xFB) ... & OP1
|
||||
{
|
||||
setHFlag(A, OP1);
|
||||
addition(B, OP1);
|
||||
}
|
||||
|
||||
:CPX OP2 is (op=0x8C | op=0x9C | op=0xAC | op=0xBC) ... & OP2
|
||||
{
|
||||
compare(X, OP2);
|
||||
}
|
||||
|
||||
:BSR REL is op=0x8D; REL
|
||||
{
|
||||
local addr:2 = inst_next;
|
||||
Push2(S, addr);
|
||||
call REL;
|
||||
}
|
||||
|
||||
:JSR EA2 is (op=0xAD | op=0xBD) ... & EA2
|
||||
{
|
||||
local addr:2 = inst_next;
|
||||
Push2(S, addr);
|
||||
local target:2 = EA2;
|
||||
call [target];
|
||||
}
|
||||
|
||||
:LDS OP2 is (op=0x8E | op=0x9E | op=0xAE | op=0xBE) ... & OP2
|
||||
{
|
||||
loadRegister(S, OP2);
|
||||
}
|
||||
|
||||
:LDX OP2 is (op=0xCE | op=0xDE | op=0xEE | op=0xFE) ... & OP2
|
||||
{
|
||||
loadRegister(X, OP2);
|
||||
}
|
||||
|
||||
:STS OP2 is (op=0x9F | op=0xAF | op=0xBF) ... & OP2
|
||||
{
|
||||
storeRegister(S, OP2);
|
||||
}
|
||||
|
||||
:STX OP2 is (op=0xDF | op=0xEF | op=0xFF) ... & OP2
|
||||
{
|
||||
storeRegister(X, OP2);
|
||||
}
|
Loading…
Reference in New Issue
Block a user