GP-4729: More OmfLoader refactoring. Initial Omf51Loader framework.

This commit is contained in:
Ryan Kurtz 2024-06-28 08:53:05 -04:00
parent 07a9507d0f
commit d58923419c
36 changed files with 940 additions and 233 deletions

View File

@ -0,0 +1,75 @@
/* ###
* 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.util.List;
import ghidra.app.util.bin.BinaryReader;
/**
* Classes that implement this interface can read various flavors of the OMF format
*/
public abstract class AbstractOmfRecordFactory {
protected BinaryReader reader;
/**
* Creates a new {@link AbstractOmfRecordFactory}
*
* @param reader The {@link BinaryReader} used to read records
*/
protected AbstractOmfRecordFactory(BinaryReader reader) {
this.reader = reader;
}
/**
* Reads the next {@link OmfRecord} pointed to by the reader
*
* @return The next read {@link OmfRecord}
* @throws IOException if there was an IO-related error
* @throws OmfException if there was a problem with the OMF specification
*/
public abstract OmfRecord readNextRecord() throws IOException, OmfException;
/**
* Gets a {@link List} of valid record types that can start a supported OMF binary
*
* @return A {@link List} of valid record types that can start a supported OMF binary
*/
public abstract List<Integer> getStartRecordTypes();
/**
* Gets a valid record type that can end a supported OMF binary
*
* @return A valid record types that can end a supported OMF binary
*/
public abstract int getEndRecordType();
/**
* {@return the reader associated with this factory}
*/
public BinaryReader getReader() {
return reader;
}
/**
* Reset this factory's reader to index 0
*/
public void reset() {
reader.setPointerIndex(0);
}
}

View File

@ -31,8 +31,12 @@ public class OmfObsoleteRecord extends OmfRecord {
* @throws IOException If an IO-related error occurred
*/
public OmfObsoleteRecord(BinaryReader reader) throws IOException {
readRecordHeader(reader);
reader.setPointerIndex(reader.getPointerIndex() + getRecordLength());
super(reader);
}
@Override
public void parseData() throws IOException, OmfException {
// No record-specific data to read
}
@Override

View File

@ -29,31 +29,48 @@ public abstract class OmfRecord implements StructConverter {
protected int recordType;
protected int recordLength;
protected byte[] data;
protected byte checkSum;
protected long recordOffset;
protected BinaryReader dataReader;
protected long dataEnd;
/**
* Reads the record header (type and length fields)
*
*/
public OmfRecord() {
// nothing to do
}
/**
* Creates a new {@link OmfRecord}
*
* @param reader A {@link BinaryReader} positioned at the start of the record
* @throws IOException if an IO-related problem occurred
* @throws IOException if there was an IO-related error
*/
public void readRecordHeader(BinaryReader reader) throws IOException {
recordOffset = reader.getPointerIndex();
recordType = reader.readNextUnsignedByte();
recordLength = reader.readNextUnsignedShort();
public OmfRecord(BinaryReader reader) throws IOException {
this.recordOffset = reader.getPointerIndex();
this.recordType = reader.readNextUnsignedByte();
this.recordLength = reader.readNextUnsignedShort();
this.data = reader.readNextByteArray(recordLength - 1);
this.checkSum = reader.readNextByte();
this.dataReader = reader.clone(recordOffset + 3);
this.dataEnd = recordOffset + 3 + recordLength - 1;
}
/**
* Reads the record checksum
* Parses this {@link OmfRecord}'s type-spefic data
*
* @param reader A {@link BinaryReader} positioned at the start of the record checksum
* @throws IOException if an IO-related problem occurred
* @throws IOException if there was an IO-related error
* @throws OmfException if there was a problem with the OMF specification
*/
public void readCheckSumByte(BinaryReader reader) throws IOException {
checkSum = reader.readNextByte();
}
public abstract void parseData() throws IOException, OmfException;
@Override
public abstract DataType toDataType() throws DuplicateNameException, IOException;
/**
* {@return the record type}
@ -76,36 +93,42 @@ public abstract class OmfRecord implements StructConverter {
return recordOffset;
}
public byte getRecordChecksum() {
return checkSum;
}
public byte[] getData() {
return data;
}
/**
* 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) {
res += reader.readNextByte();
public byte calcCheckSum() throws IOException {
byte sum = (byte) recordType;
sum += (byte) recordLength + (byte) (recordLength >> 8);
for (byte b : data) {
sum += b;
}
return res;
sum += checkSum;
return sum;
}
/**
* 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 {
public boolean validCheckSum() throws IOException {
if (checkSum == 0) {
// Some compilers just set this to zero
return true;
}
return (calcCheckSum(reader) == 0);
return (calcCheckSum() == 0);
}
/**
@ -115,9 +138,6 @@ public abstract class OmfRecord implements StructConverter {
return ((recordType & 1) != 0);
}
@Override
public abstract DataType toDataType() throws DuplicateNameException, IOException;
@Override
public String toString() {
return String.format("type: 0x%x, offset: 0x%x, length: 0x%x", recordType, recordOffset,

View File

@ -54,6 +54,11 @@ public class OmfString implements StructConverter {
return str;
}
@Override
public String toString() {
return str;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
if (length == 0) {

View File

@ -34,8 +34,12 @@ public class OmfUnknownRecord extends OmfRecord {
* @throws IOException If an IO-related error occurred
*/
public OmfUnknownRecord(BinaryReader reader) throws IOException {
readRecordHeader(reader);
reader.setPointerIndex(reader.getPointerIndex() + getRecordLength());
super(reader);
}
@Override
public void parseData() throws IOException, OmfException {
// No record-specific data to read
}
@Override

View File

@ -36,9 +36,13 @@ public class OmfUnsupportedRecord extends OmfRecord {
* @throws IOException If an IO-related error occurred
*/
public OmfUnsupportedRecord(BinaryReader reader, Class<?> recordTypesClass) throws IOException {
super(reader);
this.recordTypesClass = recordTypesClass;
readRecordHeader(reader);
reader.setPointerIndex(reader.getPointerIndex() + getRecordLength());
}
@Override
public void parseData() throws IOException, OmfException {
// No record-specific data to read
}
@Override

View File

@ -18,6 +18,8 @@ package ghidra.app.util.bin.format.omf;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.*;
@ -105,4 +107,29 @@ public class OmfUtils {
struct.setCategoryPath(new CategoryPath(OmfUtils.CATEGORY_PATH));
return struct;
}
/**
* Reads all the {@link OmfRecord records} associated with the given
* {@link AbstractOmfRecordFactory}
*
* @param factory The {@link AbstractOmfRecordFactory}
* @return A {@link List} of read {@link OmfRecord records}
* @throws IOException if there was an IO-related error
* @throws OmfException if there was a problem with the OMF specification
*/
public static List<OmfRecord> readRecords(AbstractOmfRecordFactory factory)
throws OmfException, IOException {
List<OmfRecord> records = new ArrayList<>();
factory.reset();
while (true) {
OmfRecord rec = factory.readNextRecord();
records.add(rec);
if (rec.getRecordType() == factory.getEndRecordType()) {
break;
}
}
return records;
}
}

View File

@ -20,8 +20,7 @@ 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;
import ghidra.app.util.bin.format.omf.*;
public class OmfComdatExternalSymbol extends OmfExternalSymbol {
@ -29,17 +28,17 @@ public class OmfComdatExternalSymbol extends OmfExternalSymbol {
protected List<ExternalLookup> externalLookups = new ArrayList<>();
public OmfComdatExternalSymbol(BinaryReader reader) throws IOException {
super(false);
readRecordHeader(reader);
super(reader, false);
long max = reader.getPointerIndex() + getRecordLength() - 1;
while (reader.getPointerIndex() < max) {
OmfIndex nameIndex = OmfUtils.readIndex(reader);
OmfIndex type = OmfUtils.readIndex(reader);
}
@Override
public void parseData() throws IOException, OmfException {
while (dataReader.getPointerIndex() < dataEnd) {
OmfIndex nameIndex = OmfUtils.readIndex(dataReader);
OmfIndex type = OmfUtils.readIndex(dataReader);
externalLookups.add(new ExternalLookup(nameIndex.value(), type.value()));
}
readCheckSumByte(reader);
}
public void loadNames(List<String> nameList) {

View File

@ -22,28 +22,28 @@ import ghidra.app.util.bin.format.omf.*;
public class OmfComdefRecord extends OmfExternalSymbol {
public OmfComdefRecord(BinaryReader reader, boolean isStatic) throws IOException, OmfException {
super(isStatic);
readRecordHeader(reader);
public OmfComdefRecord(BinaryReader reader, boolean isStatic) throws IOException {
super(reader, isStatic);
}
long max = reader.getPointerIndex() + getRecordLength() - 1;
while (reader.getPointerIndex() < max) {
OmfString name = OmfUtils.readString(reader);
OmfIndex typeIndex = OmfUtils.readIndex(reader);
byte dataType = reader.readNextByte();
@Override
public void parseData() throws IOException, OmfException {
while (dataReader.getPointerIndex() < dataEnd) {
OmfString name = OmfUtils.readString(dataReader);
OmfIndex typeIndex = OmfUtils.readIndex(dataReader);
byte dataType = dataReader.readNextByte();
int byteLength = 0;
if (dataType == 0x61) { // FAR data, reads numElements and elSize
int numElements = readCommunalLength(reader);
int elSize = readCommunalLength(reader);
int numElements = readCommunalLength(dataReader);
int elSize = readCommunalLength(dataReader);
byteLength = numElements * elSize;
}
else {
// Values 1 thru 5f plus 61, read the byte length
byteLength = readCommunalLength(reader);
byteLength = readCommunalLength(dataReader);
}
symbols.add(new OmfSymbol(name.str(), typeIndex.value(), 0, dataType, byteLength));
}
readCheckSumByte(reader);
}
private static int readCommunalLength(BinaryReader reader) throws OmfException, IOException {

View File

@ -40,25 +40,27 @@ public class OmfCommentRecord extends OmfRecord {
private OmfString value;
public OmfCommentRecord(BinaryReader reader) throws IOException {
readRecordHeader(reader);
commentType = reader.readNextByte();
commentClass = reader.readNextByte();
super(reader);
}
@Override
public void parseData() throws IOException, OmfException {
commentType = dataReader.readNextByte();
commentClass = dataReader.readNextByte();
switch (commentClass) {
case COMMENT_CLASS_TRANSLATOR:
case COMMENT_CLASS_DEFAULT_LIBRARY:
byte[] bytes = reader.readNextByteArray(getRecordLength() -
byte[] bytes = dataReader.readNextByteArray(getRecordLength() -
3 /* 3 = sizeof(commentType+commentClass+trailing_crcbyte*/);
value = new OmfString(bytes.length, new String(bytes, StandardCharsets.US_ASCII)); // assuming ASCII
break;
case COMMENT_CLASS_LIBMOD:
value = OmfUtils.readString(reader);
value = OmfUtils.readString(dataReader);
break;
default:
reader.setPointerIndex(reader.getPointerIndex() + getRecordLength() - 3);
break;
}
readCheckSumByte(reader);
}
public byte getCommentType() {

View File

@ -27,6 +27,10 @@ public abstract class OmfData extends OmfRecord implements Comparable<OmfData> {
protected OmfIndex segmentIndex;
protected Omf2or4 dataOffset;
public OmfData(BinaryReader reader) throws IOException {
super(reader);
}
/**
* @return get the segments index for this datablock
*/

View File

@ -18,6 +18,7 @@ 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.OmfException;
import ghidra.app.util.bin.format.omf.OmfUtils;
import ghidra.program.model.data.DataType;
import ghidra.util.exception.DuplicateNameException;
@ -27,14 +28,16 @@ public class OmfEnumeratedData extends OmfData {
private int streamLength; // Number of bytes of data
public OmfEnumeratedData(BinaryReader reader) throws IOException {
readRecordHeader(reader);
long start = reader.getPointerIndex();
segmentIndex = OmfUtils.readIndex(reader);
dataOffset = OmfUtils.readInt2Or4(reader, hasBigFields());
streamOffset = reader.getPointerIndex();
super(reader);
}
@Override
public void parseData() throws IOException, OmfException {
long start = dataReader.getPointerIndex();
segmentIndex = OmfUtils.readIndex(dataReader);
dataOffset = OmfUtils.readInt2Or4(dataReader, hasBigFields());
streamOffset = dataReader.getPointerIndex();
streamLength = getRecordLength() - 1 - (int) (streamOffset - start);
reader.setPointerIndex(streamOffset + streamLength); // Skip over the data when reading header
readCheckSumByte(reader);
}
@Override

View File

@ -33,23 +33,19 @@ public class OmfExternalSymbol extends OmfRecord {
private List<Reference> refs = new ArrayList<>();
protected OmfExternalSymbol(boolean isStatic) {
public OmfExternalSymbol(BinaryReader reader, boolean isStatic) throws IOException {
super(reader);
this.isStatic = isStatic;
}
public OmfExternalSymbol(BinaryReader reader, boolean isStatic) throws IOException {
this.isStatic = isStatic;
readRecordHeader(reader);
long max = reader.getPointerIndex() + getRecordLength() - 1;
while (reader.getPointerIndex() < max) {
OmfString name = OmfUtils.readString(reader);
OmfIndex type = OmfUtils.readIndex(reader);
@Override
public void parseData() throws IOException, OmfException {
while (dataReader.getPointerIndex() < dataEnd) {
OmfString name = OmfUtils.readString(dataReader);
OmfIndex type = OmfUtils.readIndex(dataReader);
refs.add(new Reference(name, type));
symbols.add(new OmfSymbol(name.str(), type.value(), 0, 0, 0));
}
readCheckSumByte(reader);
}
public List<OmfSymbol> getSymbols() {

View File

@ -20,7 +20,6 @@ import java.util.ArrayList;
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.*;
@ -45,12 +44,15 @@ public class OmfFileHeader extends OmfRecord {
private boolean format16bit;
public OmfFileHeader(BinaryReader reader) throws IOException {
readRecordHeader(reader);
objectName = OmfUtils.readString(reader); // This is usually the source code filename
readCheckSumByte(reader);
super(reader);
isLittleEndian = reader.isLittleEndian();
}
@Override
public void parseData() throws IOException, OmfException {
objectName = OmfUtils.readString(dataReader); // This is usually the source code filename
}
/**
* {@return the list of records}
*/
@ -261,23 +263,23 @@ public class OmfFileHeader extends OmfRecord {
/**
* Scan the object file, for the main header and comment records. Other records are parsed but not saved
* @param reader is the byte stream
* @param factory the {@link AbstractOmfRecordFactory}
* @param monitor is checked for cancellation
* @param fastscan is true if we only want to scan the header until first seghead,
* @return the header record
* @throws IOException for problems reading program data
* @throws OmfException for malformed records
*/
public static OmfFileHeader scan(BinaryReader reader, TaskMonitor monitor, boolean fastscan)
throws IOException, OmfException {
OmfRecord record = OmfRecordFactory.readRecord(reader);
public static OmfFileHeader scan(AbstractOmfRecordFactory factory, TaskMonitor monitor,
boolean fastscan) throws IOException, OmfException {
OmfRecord record = factory.readNextRecord();
if (!(record instanceof OmfFileHeader)) {
throw new OmfException("Object file does not start with proper header");
}
OmfFileHeader header = (OmfFileHeader) record;
while (true) {
record = OmfRecordFactory.readRecord(reader);
record = factory.readNextRecord();
if (monitor.isCancelled()) {
break;
@ -315,16 +317,16 @@ public class OmfFileHeader extends OmfRecord {
/**
* Parse the entire object file
*
* @param reader is the byte stream
* @param factory the {@link AbstractOmfRecordFactory}
* @param monitor is checked for cancel button
* @param log the log
* @return the header record as root of object
* @throws IOException for problems reading data
* @throws OmfException for malformed records
*/
public static OmfFileHeader parse(BinaryReader reader, TaskMonitor monitor, MessageLog log)
public static OmfFileHeader parse(AbstractOmfRecordFactory factory, TaskMonitor monitor, MessageLog log)
throws IOException, OmfException {
OmfRecord record = OmfRecordFactory.readRecord(reader);
OmfRecord record = factory.readNextRecord();
if (!(record instanceof OmfFileHeader header)) {
throw new OmfException("Object file does not start with proper header");
}
@ -332,7 +334,10 @@ public class OmfFileHeader extends OmfRecord {
OmfData lastDataBlock = null;
while (true) {
record = OmfRecordFactory.readRecord(reader);
record = factory.readNextRecord();
if (!record.validCheckSum()) {
throw new OmfException("Invalid checksum!");
}
header.records.add(record);
if (monitor.isCancelled()) {
@ -488,15 +493,6 @@ public class OmfFileHeader extends OmfRecord {
return len == stringlen + 2;
}
/**
* Create a reader for a specific OMF file
* @param provider is the underlying ByteProvider
* @return the new reader
*/
public static BinaryReader createReader(ByteProvider provider) {
return new BinaryReader(provider, true/* Always little endian */);
}
private static void logRecord(String description, OmfRecord record, MessageLog log) {
log.appendMsg(description + " (" + record + ")");
}

View File

@ -24,7 +24,7 @@ import ghidra.program.model.data.DataType;
import ghidra.util.exception.DuplicateNameException;
public class OmfFixupRecord extends OmfRecord {
private final Subrecord[] subrecs;
private Subrecord[] subrecs;
private OmfData lastData = null;
/**
@ -33,16 +33,18 @@ public class OmfFixupRecord extends OmfRecord {
* @throws IOException if there was an IO-related error
*/
public OmfFixupRecord(BinaryReader reader) throws IOException {
ArrayList<Subrecord> subreclist = new ArrayList<Subrecord>();
super(reader);
}
readRecordHeader(reader);
long max = reader.getPointerIndex() + getRecordLength() - 1;
while (reader.getPointerIndex() < max) {
subreclist.add(Subrecord.readSubrecord(reader, hasBigFields()));
@Override
public void parseData() throws IOException, OmfException {
ArrayList<Subrecord> subreclist = new ArrayList<>();
long max = dataReader.getPointerIndex() + getRecordLength() - 1;
while (dataReader.getPointerIndex() < max) {
subreclist.add(Subrecord.readSubrecord(dataReader, hasBigFields()));
}
subrecs = new Subrecord[subreclist.size()];
subreclist.toArray(subrecs);
readCheckSumByte(reader);
}
/**

View File

@ -34,15 +34,17 @@ public class OmfGroupRecord extends OmfRecord {
private GroupSubrecord[] group;
public OmfGroupRecord(BinaryReader reader) throws IOException {
readRecordHeader(reader);
long max = reader.getPointerIndex() + getRecordLength() - 1;
groupNameIndex = OmfUtils.readIndex(reader);
ArrayList<GroupSubrecord> grouplist = new ArrayList<GroupSubrecord>();
while (reader.getPointerIndex() < max) {
GroupSubrecord subrec = GroupSubrecord.read(reader);
super(reader);
}
@Override
public void parseData() throws IOException, OmfException {
groupNameIndex = OmfUtils.readIndex(dataReader);
ArrayList<GroupSubrecord> grouplist = new ArrayList<>();
while (dataReader.getPointerIndex() < dataEnd) {
GroupSubrecord subrec = GroupSubrecord.read(dataReader);
grouplist.add(subrec);
}
readCheckSumByte(reader);
group = new GroupSubrecord[grouplist.size()];
grouplist.toArray(group);
}

View File

@ -19,8 +19,7 @@ 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.app.util.bin.format.omf.*;
import ghidra.program.model.data.DataType;
import ghidra.util.exception.DuplicateNameException;
@ -30,17 +29,19 @@ public class OmfIteratedData extends OmfData {
private DataBlock[] datablock;
public OmfIteratedData(BinaryReader reader) throws IOException {
readRecordHeader(reader);
long max = reader.getPointerIndex() + getRecordLength() - 1;
super(reader);
}
@Override
public void parseData() throws IOException, OmfException {
boolean hasBigFields = 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);
segmentIndex = OmfUtils.readIndex(dataReader);
dataOffset = OmfUtils.readInt2Or4(dataReader, hasBigFields);
ArrayList<DataBlock> blocklist = new ArrayList<>();
while (dataReader.getPointerIndex() < dataEnd) {
DataBlock block = DataBlock.read(dataReader, hasBigFields);
blocklist.add(block);
}
readCheckSumByte(reader);
datablock = new DataBlock[blocklist.size()];
blocklist.toArray(datablock);
}

View File

@ -19,13 +19,14 @@ 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.app.util.bin.format.omf.AbstractOmfRecordFactory;
import ghidra.app.util.bin.format.omf.OmfException;
import ghidra.util.task.TaskMonitor;
@SuppressWarnings("unused")
public class OmfLibraryRecord extends OmfRecord {
public class OmfLibraryRecord {
private int recordType;
private int recordLength;
private int pageSize; // All archive members must start on a page boundary of this size
private long dictionaryOffset;
private int dictionarySize;
@ -40,13 +41,14 @@ public class OmfLibraryRecord extends OmfRecord {
public String machineName;
}
public OmfLibraryRecord(BinaryReader reader) throws IOException {
readRecordHeader(reader);
public OmfLibraryRecord(BinaryReader reader) throws IOException, OmfException {
recordType = reader.readNextUnsignedByte();
recordLength = reader.readNextUnsignedShort();
pageSize = recordLength + 3;
dictionaryOffset = reader.readNextInt() & 0xffffffff;
dictionarySize = reader.readNextShort() & 0xffff;
flags = reader.readNextByte();
// No checksum byte (just padding)
// No checksum byte
}
public int getPageSize() {
@ -88,9 +90,10 @@ public class OmfLibraryRecord extends OmfRecord {
return true;
}
public static OmfLibraryRecord parse(BinaryReader reader, TaskMonitor monitor)
throws IOException {
public static OmfLibraryRecord parse(AbstractOmfRecordFactory factory, TaskMonitor monitor)
throws IOException, OmfException {
OmfLibraryRecord res = null;
BinaryReader reader = factory.getReader();
byte type = reader.peekNextByte();
if (type != (byte) 0xF0) {
throw new IOException("Not an OMF Library record");
@ -104,7 +107,7 @@ public class OmfLibraryRecord extends OmfRecord {
curheader.payloadOffset = reader.getPointerIndex();
OmfFileHeader fileheader;
try {
fileheader = OmfFileHeader.scan(reader, monitor, false);
fileheader = OmfFileHeader.scan(factory, monitor, false);
}
catch (OmfException e) {
throw new IOException("Could not parse individual object file within archive");
@ -122,9 +125,4 @@ public class OmfLibraryRecord extends OmfRecord {
}
return res;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
return OmfUtils.toOmfRecordDataType(this, OmfRecordTypes.getName(recordType));
}
}

View File

@ -18,38 +18,20 @@ 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.app.util.bin.format.omf.*;
import ghidra.program.model.data.DataType;
import ghidra.util.exception.DuplicateNameException;
public class OmfModuleEnd extends OmfRecord {
//private byte moduleType;
//private OmfFixupRecord.FixupTarget startAddress;
public OmfModuleEnd(BinaryReader reader) throws IOException {
readRecordHeader(reader);
/* The record type is not handled so simply skip the information
moduleType = reader.readNextByte();
if (hasStartAddress()) {
endData = reader.readNextByte();
frameDatum = readInt1Or2(reader, hasBigFields());
targetDatum = readInt1Or2(reader, hasBigFields());
targetDisplacement readInt2Or4(reader, hasBigFields());
}
readCheckSumByte(reader);
*/
reader.setPointerIndex(reader.getPointerIndex() + getRecordLength());
}
/*
public boolean isMainProgramModule() {
return ((moduleType & 0x80) != 0);
super(reader);
}
public boolean hasStartAddress() {
return ((moduleType & 0x40) != 0);
@Override
public void parseData() throws IOException, OmfException {
// No record-specific data to read
}
*/
@Override
public DataType toDataType() throws DuplicateNameException, IOException {

View File

@ -28,12 +28,14 @@ public class OmfNamesRecord extends OmfRecord {
private List<OmfString> names = new ArrayList<>();
public OmfNamesRecord(BinaryReader reader) throws IOException {
readRecordHeader(reader);
long max = reader.getPointerIndex() + getRecordLength() - 1;
while (reader.getPointerIndex() < max) {
names.add(OmfUtils.readString(reader));
super(reader);
}
@Override
public void parseData() throws IOException, OmfException {
while (dataReader.getPointerIndex() < dataEnd) {
names.add(OmfUtils.readString(dataReader));
}
readCheckSumByte(reader);
}
public void appendNames(List<String> namelist) {

View File

@ -18,15 +18,30 @@ package ghidra.app.util.bin.format.omf.omf;
import static ghidra.app.util.bin.format.omf.omf.OmfRecordTypes.*;
import java.io.IOException;
import java.util.List;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.format.omf.*;
public class OmfRecordFactory {
/**
* A class for reading/creating Relocatable OMF records
*/
public class OmfRecordFactory extends AbstractOmfRecordFactory {
public static OmfRecord readRecord(BinaryReader reader) throws IOException, OmfException {
/**
* Creates a new {@link OmfRecordFactory}
*
* @param provider The {@link ByteProvider} that contains the records
*/
public OmfRecordFactory(ByteProvider provider) {
super(new BinaryReader(provider, true));
}
@Override
public OmfRecord readNextRecord() throws IOException, OmfException {
int type = Byte.toUnsignedInt(reader.peekNextByte());
return switch (type & 0xfffffffe) { // mask off the least significant bit (16/32 bit flag)
OmfRecord record = switch (type & 0xfffffffe) { // mask off the least significant bit (16/32 bit flag)
case THEADR:
case LHEADR:
yield new OmfFileHeader(reader);
@ -91,5 +106,18 @@ public class OmfRecordFactory {
default:
yield new OmfUnknownRecord(reader);
};
record.parseData();
return record;
}
@Override
public List<Integer> getStartRecordTypes() {
return List.of(THEADR, LHEADR);
}
@Override
public int getEndRecordType() {
return MODEND;
}
}

View File

@ -17,6 +17,11 @@ package ghidra.app.util.bin.format.omf.omf;
import ghidra.app.util.bin.format.omf.OmfUtils;
/**
* Relocatable OMF record types
*
* @see <a href="http://www.azillionmonkeys.com/qed/Omfg.pdf">OMF: Relocatable Object Module Format</a>
*/
public class OmfRecordTypes {
public final static int RHEADR = 0x6E; // Obsolete
@ -62,6 +67,7 @@ public class OmfRecordTypes {
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;

View File

@ -83,20 +83,23 @@ public class OmfSegmentHeader extends OmfRecord {
}
public OmfSegmentHeader(BinaryReader reader) throws IOException {
readRecordHeader(reader);
super(reader);
}
@Override
public void parseData() throws IOException, OmfException {
boolean hasBigFields = hasBigFields();
segAttr = reader.readNextByte();
segAttr = dataReader.readNextByte();
int A = (segAttr >> 5) & 7;
if (A == 0) {
frameNumber = reader.readNextShort() & 0xffff;
offset = reader.readNextByte() & 0xff;
frameNumber = dataReader.readNextShort() & 0xffff;
offset = dataReader.readNextByte() & 0xff;
vma = (long) frameNumber + offset;
}
segmentLength = OmfUtils.readInt2Or4(reader, hasBigFields);
segmentNameIndex = OmfUtils.readIndex(reader);
classNameIndex = OmfUtils.readIndex(reader);
overlayNameIndex = OmfUtils.readIndex(reader);
readCheckSumByte(reader);
segmentLength = OmfUtils.readInt2Or4(dataReader, hasBigFields);
segmentNameIndex = OmfUtils.readIndex(dataReader);
classNameIndex = OmfUtils.readIndex(dataReader);
overlayNameIndex = OmfUtils.readIndex(dataReader);
int B = (segAttr >> 1) & 1;
if (B == 1) { // Ignore the segmentLength field
if (getRecordType() == OmfRecordTypes.SEGDEF) {
@ -393,10 +396,10 @@ public class OmfSegmentHeader extends OmfRecord {
*/
private void establishNextBuffer() throws IOException {
while (dataUpNext < dataBlocks.size()) {
OmfData data = dataBlocks.get(dataUpNext);
if (pointer < data.getDataOffset()) {
OmfData omfData = dataBlocks.get(dataUpNext);
if (pointer < omfData.getDataOffset()) {
// We have some fill to produce before the next section
long size = data.getDataOffset() - pointer;
long size = omfData.getDataOffset() - pointer;
if (size > OmfLoader.MAX_UNINITIALIZED_FILL) {
throw new IOException(
"Unfilled hole in OMF data blocks for segment: " + segmentName);
@ -408,8 +411,8 @@ public class OmfSegmentHeader extends OmfRecord {
bufferpointer = 0;
return;
}
else if (pointer == data.getDataOffset()) {
buffer = data.getByteArray(reader);
else if (pointer == omfData.getDataOffset()) {
buffer = omfData.getByteArray(reader);
bufferpointer = 0;
dataUpNext++;
if (buffer.length == 0) {
@ -421,7 +424,7 @@ public class OmfSegmentHeader extends OmfRecord {
dataUpNext++;
throw new IOException(String.format(
"Segment %s:%s has bad data offset (0x%x) in data block %d...skipping.",
segmentName, className, data.getDataOffset(), dataUpNext - 1));
segmentName, className, omfData.getDataOffset(), dataUpNext - 1));
}
}
// We may have filler after the last block

View File

@ -35,26 +35,28 @@ public class OmfSymbolRecord extends OmfRecord {
private record Reference(OmfString name, Omf2or4 offset, OmfIndex type) {}
public OmfSymbolRecord(BinaryReader reader, boolean isStatic) throws IOException {
super(reader);
this.isStatic = isStatic;
readRecordHeader(reader);
long max = reader.getPointerIndex() + getRecordLength() - 1;
}
@Override
public void parseData() throws IOException {
boolean hasBigFields = hasBigFields();
baseGroupIndex = OmfUtils.readIndex(reader);
baseSegmentIndex = OmfUtils.readIndex(reader);
baseGroupIndex = OmfUtils.readIndex(dataReader);
baseSegmentIndex = OmfUtils.readIndex(dataReader);
if (baseSegmentIndex.value() == 0) {
baseFrame = reader.readNextUnsignedShort();
baseFrame = dataReader.readNextUnsignedShort();
}
ArrayList<OmfSymbol> symbollist = new ArrayList<OmfSymbol>();
while (reader.getPointerIndex() < max) {
OmfString name = OmfUtils.readString(reader);
Omf2or4 offset = OmfUtils.readInt2Or4(reader, hasBigFields);
OmfIndex type = OmfUtils.readIndex(reader);
while (dataReader.getPointerIndex() < dataEnd) {
OmfString name = OmfUtils.readString(dataReader);
Omf2or4 offset = OmfUtils.readInt2Or4(dataReader, hasBigFields);
OmfIndex type = OmfUtils.readIndex(dataReader);
OmfSymbol subrec = new OmfSymbol(name.str(), type.value(), offset.value(), 0, 0);
symbollist.add(subrec);
refs.add(new Reference(name, offset, type));
}
readCheckSumByte(reader);
symbol = new OmfSymbol[symbollist.size()];
symbollist.toArray(symbol);
}
@ -107,5 +109,4 @@ public class OmfSymbolRecord extends OmfRecord {
struct.setCategoryPath(new CategoryPath(OmfUtils.CATEGORY_PATH));
return struct;
}
}

View File

@ -0,0 +1,81 @@
/* ###
* 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.omf166;
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;
public class Omf166DepList extends OmfRecord {
private record Info(byte type, Byte mark, Integer time, OmfString name) {}
private List<Info> infoList = new ArrayList<>();
public Omf166DepList(BinaryReader reader) throws IOException {
super(reader);
}
@Override
public void parseData() throws IOException, OmfException {
while (dataReader.getPointerIndex() < dataEnd) {
byte iTyp = dataReader.readNextByte();
switch (iTyp) {
case 0x00:
case 0x01:
case 0x02:
case 0x03:
case 0x04:
byte mark = dataReader.readNextByte();
int time = dataReader.readNextInt();
OmfString name = OmfUtils.readString(dataReader);
infoList.add(new Info(iTyp, mark, time, name));
break;
case (byte) 0xff:
OmfString invocation = OmfUtils.readString(dataReader);
infoList.add(new Info(iTyp, null, null, invocation));
break;
default:
throw new OmfException("Unexpected DEPLST iTyp: 0x%x".formatted(iTyp));
}
}
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType struct = new StructureDataType(Omf166RecordTypes.getName(recordType), 0);
struct.add(BYTE, "type", null);
struct.add(WORD, "length", null);
for (Info info : infoList) {
struct.add(BYTE, "iTyp", null);
if (info.mark != null) {
struct.add(BYTE, "mark8", null);
}
if (info.time != null) {
struct.add(DWORD, "time32", null);
}
struct.add(info.name.toDataType(), "name", null);
}
struct.add(BYTE, "checksum", null);
struct.setCategoryPath(new CategoryPath(OmfUtils.CATEGORY_PATH));
return struct;
}
}

View File

@ -0,0 +1,73 @@
/* ###
* 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.omf166;
import ghidra.app.util.bin.format.omf.OmfUtils;
/**
* OMF-166 record types
*
* @see <a href="https://www.keil.com/download/files/omf166.pdf">OMF-166 Description</a>
*/
public class Omf166RecordTypes {
public final static int RTXDEF = 0x30;
public final static int DEPLST = 0x70;
public final static int REGMSK = 0x72;
public final static int TYPNEW = 0xF0;
public final static int BLKEND = 0x7C;
public final static int THEADR = 0x80;
public final static int LHEADR = 0x82;
public final static int COMMENT = 0x88;
public final static int MODEND = 0x8A;
public final static int LINNUM = 0x94;
public final static int LNAMES = 0x96;
public final static int LIBLOC = 0xA8;
public final static int LIBNAMES = 0xA6;
public final static int LIBDICT = 0xAA;
public final static int LIBHDR = 0xBA;
public final static int PHEADR = 0xE0;
public final static int PECDEF = 0xE4;
public final static int SSKDEF = 0xE5;
public final static int MODINF = 0xE7;
public final static int TSKDEF = 0xE1;
public final static int REGDEF = 0xE3;
public final static int SEDEF = 0xB0;
public final static int TYPDEF = 0xB2;
public final static int GRPDEF = 0xB1;
public final static int PUBDEF = 0xB3;
public final static int GLBDEF = 0xE6;
public final static int EXTDEF = 0x8C;
public final static int LOCSYM = 0xB5;
public final static int BLKDEF = 0xB7;
public final static int DEBSYM = 0xB6;
public final static int LEDATA = 0xB8;
public final static int PEDATA = 0xB9;
public final static int VECTAB = 0xE9;
public final static int FIXUPP = 0xB4;
public final static int TSKEND = 0xE2;
public final static int XSECDEF = 0xC5;
/**
* 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, Omf166RecordTypes.class);
}
}

View File

@ -0,0 +1,70 @@
/* ###
* 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.omf51;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.omf.*;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
public class Omf51ModuleEnd extends OmfRecord {
private OmfString moduleName;
private byte regMsk;
/**
* Creates a new {@link Omf51ModuleEnd} record
*
* @param reader A {@link BinaryReader} positioned at the start of the record
* @throws IOException if an IO-related error occurred
*/
public Omf51ModuleEnd(BinaryReader reader) throws IOException {
super(reader);
}
@Override
public void parseData() throws IOException, OmfException {
moduleName = OmfUtils.readString(dataReader);
dataReader.readNextByte();
dataReader.readNextByte();
regMsk = dataReader.readNextByte();
dataReader.readNextByte();
}
/**
* {@return the register mask}
*/
public byte getRegisterMask() {
return regMsk;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType struct = new StructureDataType(Omf51RecordTypes.getName(recordType), 0);
struct.add(BYTE, "type", null);
struct.add(WORD, "length", null);
struct.add(moduleName.toDataType(), "name", null);
struct.add(WORD, "padding", null);
struct.add(BYTE, "REG MSK", null);
struct.add(BYTE, "padding", null);
struct.add(BYTE, "checksum", null);
struct.setCategoryPath(new CategoryPath(OmfUtils.CATEGORY_PATH));
return struct;
}
}

View File

@ -0,0 +1,67 @@
/* ###
* 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.omf51;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.omf.*;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
public class Omf51ModuleHeader extends OmfRecord {
private OmfString moduleName;
private byte trnId;
/**
* Creates a new {@link Omf51ModuleHeader} record
*
* @param reader A {@link BinaryReader} positioned at the start of the record
* @throws IOException if an IO-related error occurred
*/
public Omf51ModuleHeader(BinaryReader reader) throws IOException {
super(reader);
}
@Override
public void parseData() throws IOException, OmfException {
moduleName = OmfUtils.readString(dataReader);
dataReader.readNextByte();
trnId = dataReader.readNextByte();
}
/**
* {@return the TRN ID}
*/
public byte getTrnId() {
return trnId;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType struct = new StructureDataType(Omf51RecordTypes.getName(recordType), 0);
struct.add(BYTE, "type", null);
struct.add(WORD, "length", null);
struct.add(moduleName.toDataType(), "name", null);
struct.add(BYTE, "padding", null);
struct.add(BYTE, "TRN ID", null);
struct.add(BYTE, "checksum", null);
struct.setCategoryPath(new CategoryPath(OmfUtils.CATEGORY_PATH));
return struct;
}
}

View File

@ -0,0 +1,83 @@
/* ###
* 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.omf51;
import static ghidra.app.util.bin.format.omf.omf51.Omf51RecordTypes.*;
import java.io.IOException;
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.bin.format.omf.omf166.Omf166RecordTypes;
import ghidra.app.util.bin.format.omf.omf166.Omf166DepList;
/**
* A class for reading/creating OMF-51 records
*/
public class Omf51RecordFactory extends AbstractOmfRecordFactory {
/**
* Creates a new {@link Omf51RecordFactory}
*
* @param provider The {@link ByteProvider} that contains the records
*/
public Omf51RecordFactory(ByteProvider provider) {
super(new BinaryReader(provider, true));
}
@Override
public OmfRecord readNextRecord() throws IOException, OmfException {
int type = Byte.toUnsignedInt(reader.peekNextByte());
OmfRecord record = switch (type) {
case ModuleHDR:
yield new Omf51ModuleHeader(reader);
case ModuleEND:
yield new Omf51ModuleEnd(reader);
case Omf166RecordTypes.DEPLST:
yield new Omf166DepList(reader);
case Content:
case Fixup:
case SegmentDEF:
case ScopeDEF:
case DebugItem:
case PublicDEF:
case ExternalDEF:
case LibModLocs:
case LibModName:
case LibDictionary:
case LibHeader:
yield new OmfUnsupportedRecord(reader, Omf51RecordTypes.class);
default:
yield new OmfUnknownRecord(reader);
};
record.parseData();
return record;
}
@Override
public List<Integer> getStartRecordTypes() {
return List.of(ModuleHDR, Omf166RecordTypes.DEPLST);
}
@Override
public int getEndRecordType() {
return ModuleEND;
}
}

View File

@ -0,0 +1,50 @@
/* ###
* 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.omf51;
import ghidra.app.util.bin.format.omf.OmfUtils;
/**
* OMF-51 record types
*
* @see <a href="https://turbo51.com/documentation/omf-51-object-module-format">OMF-51 Object Module Format</a>
*/
public class Omf51RecordTypes {
public final static int ModuleHDR = 0x02;
public final static int ModuleEND = 0x04;
public final static int Content = 0x06;
public final static int Fixup = 0x08;
public final static int SegmentDEF = 0x0e;
public final static int ScopeDEF = 0x10;
public final static int DebugItem = 0x12;
public final static int PublicDEF = 0x16;
public final static int ExternalDEF = 0x18;
public final static int LibModLocs = 0x26;
public final static int LibModName = 0x28;
public final static int LibDictionary = 0x2a;
public final static int LibHeader = 0x2c;
/**
* 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, Omf51RecordTypes.class);
}
}

View File

@ -0,0 +1,111 @@
/* ###
* 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.opinion;
import java.io.IOException;
import java.util.*;
import ghidra.app.util.MemoryBlockUtils;
import ghidra.app.util.Option;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.format.omf.*;
import ghidra.app.util.bin.format.omf.omf51.Omf51RecordFactory;
import ghidra.app.util.importer.MessageLog;
import ghidra.program.database.mem.FileBytes;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.data.DataUtilities;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* A {@link Loader} for OMF-51 files
*/
public class Omf51Loader extends AbstractProgramWrapperLoader {
public final static String OMF51_NAME = "Object Module Format (OMF-51)";
public final static long MIN_BYTE_LENGTH = 11;
@Override
public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException {
List<LoadSpec> loadSpecs = new ArrayList<>();
if (provider.length() < MIN_BYTE_LENGTH) {
return loadSpecs;
}
AbstractOmfRecordFactory factory = new Omf51RecordFactory(provider);
try {
OmfRecord first = factory.readNextRecord();
if (factory.getStartRecordTypes().contains(first.getRecordType()) &&
first.validCheckSum()) {
List<QueryResult> results = QueryOpinionService.query(getName(), "8051", null);
for (QueryResult result : results) {
loadSpecs.add(new LoadSpec(this, 0, result));
}
if (loadSpecs.isEmpty()) {
loadSpecs.add(new LoadSpec(this, 0, true));
}
}
}
catch (IOException | OmfException e) {
// that's ok, not an OMF-51
}
return loadSpecs;
}
@Override
protected void load(ByteProvider provider, LoadSpec loadSpec, List<Option> options,
Program program, TaskMonitor monitor, MessageLog log)
throws IOException, CancelledException {
FileBytes fileBytes = MemoryBlockUtils.createFileBytes(program, provider, monitor);
AbstractOmfRecordFactory factory = new Omf51RecordFactory(provider);
try {
List<OmfRecord> records = OmfUtils.readRecords(factory);
markupRecords(program, fileBytes, records, log, monitor);
}
catch (OmfException e) {
throw new IOException(e);
}
}
private void markupRecords(Program program, FileBytes fileBytes, List<OmfRecord> records,
MessageLog log, TaskMonitor monitor) {
monitor.setMessage("Marking up records...");
int size = records.stream().mapToInt(r -> r.getRecordLength() + 3).sum();
try {
Address recordSpaceAddr = AddressSpace.OTHER_SPACE.getAddress(0);
MemoryBlock headerBlock = MemoryBlockUtils.createInitializedBlock(program, true,
"RECORDS", recordSpaceAddr, fileBytes, 0, size, "", "", false, false, false, log);
Address start = headerBlock.getStart();
for (OmfRecord record : records) {
DataUtilities.createData(program, start.add(record.getRecordOffset()),
record.toDataType(), -1, DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
}
}
catch (Exception e) {
log.appendMsg("Failed to markup records");
}
}
@Override
public String getName() {
return OMF51_NAME;
}
}

View File

@ -42,6 +42,9 @@ import ghidra.util.exception.CancelledException;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitor;
/**
* A {@link Loader} for Relocatable Object Module (OMF) files
*/
public class OmfLoader extends AbstractProgramWrapperLoader {
public final static String OMF_NAME = "Relocatable Object Module Format (OMF)";
public final static long MIN_BYTE_LENGTH = 11;
@ -59,25 +62,14 @@ public class OmfLoader extends AbstractProgramWrapperLoader {
* @return the "secondary constraint"
*/
private String mapTranslator(String record) {
if (record == null) {
return null;
}
if (record.startsWith("Borland")) {
return "borlandcpp";
}
if (record.startsWith("Delphi")) {
return "borlanddelphi";
}
if (record.startsWith("CodeGear")) {
return "codegearcpp";
}
if (record.equals("MS C")) {
return "windows";
}
if (record.startsWith("Watcom")) {
return "watcom";
}
return null;
return switch (record) {
case String s when s.startsWith("Borland") -> "boarlandcpp";
case String s when s.startsWith("Delphi") -> "borlanddelphi";
case String s when s.startsWith("CodeGear") -> "codegearcpp";
case String s when s.equals("MS C") -> "windows";
case String s when s.startsWith("Watcom") -> "watcom";
default -> null;
};
}
@Override
@ -88,12 +80,12 @@ public class OmfLoader extends AbstractProgramWrapperLoader {
return loadSpecs;
}
BinaryReader reader = OmfFileHeader.createReader(provider);
if (OmfFileHeader.checkMagicNumber(reader)) {
reader.setPointerIndex(0);
AbstractOmfRecordFactory factory = new OmfRecordFactory(provider);
if (OmfFileHeader.checkMagicNumber(factory.getReader())) {
factory.reset();
OmfFileHeader scan;
try {
scan = OmfFileHeader.scan(reader, TaskMonitor.DUMMY, true);
scan = OmfFileHeader.scan(factory, TaskMonitor.DUMMY, true);
}
catch (OmfException e) {
throw new IOException("Bad header format: " + e.getMessage());
@ -121,9 +113,9 @@ public class OmfLoader extends AbstractProgramWrapperLoader {
throws IOException, CancelledException {
OmfFileHeader header = null;
BinaryReader reader = OmfFileHeader.createReader(provider);
AbstractOmfRecordFactory factory = new OmfRecordFactory(provider);
try {
header = OmfFileHeader.parse(reader, monitor, log);
header = OmfFileHeader.parse(factory, monitor, log);
header.resolveNames();
header.sortSegmentDataBlocks();
OmfFileHeader.doLinking(IMAGE_BASE, header.getSegments(), header.getGroups());
@ -141,7 +133,7 @@ public class OmfLoader extends AbstractProgramWrapperLoader {
FileBytes fileBytes = MemoryBlockUtils.createFileBytes(program, provider, monitor);
try {
processSegmentHeaders(reader, header, program, monitor, log);
processSegmentHeaders(factory.getReader(), header, program, monitor, log);
processPublicSymbols(header, program, monitor, log);
processExternalSymbols(header, program, monitor, log);
processRelocations(header, program, monitor, log);

View File

@ -20,9 +20,11 @@ import static ghidra.formats.gfilesystem.fileinfo.FileAttributeType.*;
import java.io.IOException;
import java.util.ArrayList;
import ghidra.app.util.bin.*;
import ghidra.app.util.bin.format.omf.omf.OmfFileHeader;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.ByteProviderWrapper;
import ghidra.app.util.bin.format.omf.OmfException;
import ghidra.app.util.bin.format.omf.omf.OmfLibraryRecord;
import ghidra.app.util.bin.format.omf.omf.OmfRecordFactory;
import ghidra.formats.gfilesystem.*;
import ghidra.formats.gfilesystem.annotations.FileSystemInfo;
import ghidra.formats.gfilesystem.fileinfo.FileAttributes;
@ -38,10 +40,10 @@ public class OmfArchiveFileSystem extends AbstractFileSystem<OmfLibraryRecord.Me
this.provider = provider;
}
public void mount(TaskMonitor monitor) throws IOException {
public void mount(TaskMonitor monitor) throws IOException, OmfException {
monitor.setMessage("Opening OMF archive...");
BinaryReader reader = OmfFileHeader.createReader(provider);
OmfLibraryRecord libraryRec = OmfLibraryRecord.parse(reader, monitor);
OmfLibraryRecord libraryRec =
OmfLibraryRecord.parse(new OmfRecordFactory(provider), monitor);
ArrayList<OmfLibraryRecord.MemberHeader> memberHeaders = libraryRec.getMemberHeaders();
for (OmfLibraryRecord.MemberHeader member : memberHeaders) {
String name = member.name;

View File

@ -17,10 +17,11 @@ package ghidra.file.formats.omf;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.format.omf.omf.OmfFileHeader;
import ghidra.app.util.bin.format.omf.AbstractOmfRecordFactory;
import ghidra.app.util.bin.format.omf.OmfException;
import ghidra.app.util.bin.format.omf.omf.OmfLibraryRecord;
import ghidra.app.util.bin.format.omf.omf.OmfRecordFactory;
import ghidra.app.util.opinion.OmfLoader;
import ghidra.formats.gfilesystem.FSRLRoot;
import ghidra.formats.gfilesystem.FileSystemService;
@ -38,7 +39,12 @@ public class OmfArchiveFileSystemFactory implements
throws IOException, CancelledException {
OmfArchiveFileSystem fs = new OmfArchiveFileSystem(targetFSRL, byteProvider);
fs.mount(monitor);
try {
fs.mount(monitor);
}
catch (OmfException e) {
throw new IOException(e);
}
return fs;
}
@ -51,8 +57,8 @@ public class OmfArchiveFileSystemFactory implements
}
try {
BinaryReader reader = OmfFileHeader.createReader(byteProvider);
return OmfLibraryRecord.checkMagicNumber(reader);
AbstractOmfRecordFactory factory = new OmfRecordFactory(byteProvider);
return OmfLibraryRecord.checkMagicNumber(factory.getReader());
}
catch (IOException e) {
return false;

View File

@ -8,6 +8,7 @@ data/languages/80390.cspec||GHIDRA||||END|
data/languages/80390.slaspec||GHIDRA||||END|
data/languages/8051.cspec||GHIDRA||||END|
data/languages/8051.ldefs||GHIDRA||||END|
data/languages/8051.opinion||GHIDRA||||END|
data/languages/8051.pspec||GHIDRA||||END|
data/languages/8051.slaspec||GHIDRA||||END|
data/languages/8051_archimedes.cspec||GHIDRA||||END|

View File

@ -0,0 +1,7 @@
<opinions>
<constraint loader="Object Module Format (OMF-51)">
<constraint compilerSpecID="default">
<constraint primary="8051" processor="8051" endian="big" size="16" />
</constraint>
</constraint>
</opinions>