Merge branch 'GP-2997_ryanmkurtz_PR-4857_Gravelbones_omf_alias'

(Closes #4856, Closes #4857)
This commit is contained in:
Ryan Kurtz 2023-01-10 09:56:41 -05:00
commit 1a36ad806e
20 changed files with 714 additions and 556 deletions

View file

@ -22,17 +22,17 @@ import ghidra.app.util.bin.BinaryReader;
public class OmfComdefRecord extends OmfExternalSymbol { public class OmfComdefRecord extends OmfExternalSymbol {
public OmfComdefRecord(BinaryReader reader,boolean isStatic) throws IOException, OmfException { public OmfComdefRecord(BinaryReader reader, boolean isStatic) throws IOException, OmfException {
super(isStatic); super(isStatic);
readRecordHeader(reader); readRecordHeader(reader);
long max = reader.getPointerIndex() + getRecordLength() - 1; long max = reader.getPointerIndex() + getRecordLength() - 1;
ArrayList<OmfSymbol> symbollist = new ArrayList<OmfSymbol>(); ArrayList<OmfSymbol> symbollist = new ArrayList<OmfSymbol>();
while(reader.getPointerIndex() < max) { while (reader.getPointerIndex() < max) {
String name = OmfRecord.readString(reader); String name = OmfRecord.readString(reader);
int typeIndex = OmfRecord.readIndex(reader); int typeIndex = OmfRecord.readIndex(reader);
byte dataType = reader.readNextByte(); byte dataType = reader.readNextByte();
int byteLength=0; int byteLength = 0;
if (dataType == 0x61) { // FAR data, reads numElements and elSize if (dataType == 0x61) { // FAR data, reads numElements and elSize
int numElements = readCommunalLength(reader); int numElements = readCommunalLength(reader);
int elSize = readCommunalLength(reader); int elSize = readCommunalLength(reader);
@ -42,18 +42,19 @@ public class OmfComdefRecord extends OmfExternalSymbol {
// Values 1 thru 5f plus 61, read the byte length // Values 1 thru 5f plus 61, read the byte length
byteLength = readCommunalLength(reader); byteLength = readCommunalLength(reader);
} }
OmfSymbol sym = new OmfSymbol(name,typeIndex,0,dataType,byteLength); OmfSymbol sym = new OmfSymbol(name, typeIndex, 0, dataType, byteLength);
symbollist.add(sym); symbollist.add(sym);
} }
readCheckSumByte(reader); readCheckSumByte(reader);
symbol = new OmfSymbol[symbollist.size()]; symbol = new OmfSymbol[symbollist.size()];
symbollist.toArray(symbol); symbollist.toArray(symbol);
} }
private static int readCommunalLength(BinaryReader reader) throws OmfException, IOException { private static int readCommunalLength(BinaryReader reader) throws OmfException, IOException {
int val = reader.readNextByte() & 0xff; int val = reader.readNextByte() & 0xff;
if (val <= 128) if (val <= 128) {
return val; return val;
}
if (val == 0x81) { if (val == 0x81) {
val = reader.readNextShort() & 0xffff; val = reader.readNextShort() & 0xffff;
} }
@ -65,9 +66,10 @@ public class OmfComdefRecord extends OmfExternalSymbol {
else if (val == 0x88) { else if (val == 0x88) {
val = reader.readNextInt(); val = reader.readNextInt();
} }
else else {
throw new OmfException("Illegal communal length encoding"); throw new OmfException("Illegal communal length encoding");
}
return val; return val;
} }
} }

View file

@ -31,7 +31,7 @@ public class OmfCommentRecord extends OmfRecord {
private byte commentType; private byte commentType;
private byte commentClass; private byte commentClass;
private String value; private String value;
public OmfCommentRecord(BinaryReader reader) throws IOException { public OmfCommentRecord(BinaryReader reader) throws IOException {
readRecordHeader(reader); readRecordHeader(reader);
commentType = reader.readNextByte(); commentType = reader.readNextByte();
@ -45,11 +45,15 @@ public class OmfCommentRecord extends OmfRecord {
} }
readCheckSumByte(reader); readCheckSumByte(reader);
} }
public byte getCommentType() {
return commentType;
}
public byte getCommentClass() { public byte getCommentClass() {
return commentClass; return commentClass;
} }
public String getValue() { public String getValue() {
return value; return value;
} }

View file

@ -31,11 +31,11 @@ public class OmfEnumeratedData extends OmfRecord implements OmfData {
segmentIndex = OmfRecord.readIndex(reader); segmentIndex = OmfRecord.readIndex(reader);
dataOffset = OmfRecord.readInt2Or4(reader, hasBigFields()) & 0xffffffffL; dataOffset = OmfRecord.readInt2Or4(reader, hasBigFields()) & 0xffffffffL;
streamOffset = reader.getPointerIndex(); streamOffset = reader.getPointerIndex();
streamLength = getRecordLength() - 1 - (int)(streamOffset - start); streamLength = getRecordLength() - 1 - (int) (streamOffset - start);
reader.setPointerIndex(streamOffset + streamLength); // Skip over the data when reading header reader.setPointerIndex(streamOffset + streamLength); // Skip over the data when reading header
readCheckSumByte(reader); readCheckSumByte(reader);
} }
public int getSegmentIndex() { public int getSegmentIndex() {
return segmentIndex; return segmentIndex;
} }
@ -49,7 +49,7 @@ public class OmfEnumeratedData extends OmfRecord implements OmfData {
public int getLength() { public int getLength() {
return streamLength; return streamLength;
} }
@Override @Override
public int compareTo(OmfData o) { public int compareTo(OmfData o) {
long otherOffset = o.getDataOffset(); long otherOffset = o.getDataOffset();

View file

@ -15,32 +15,32 @@
*/ */
package ghidra.app.util.bin.format.omf; package ghidra.app.util.bin.format.omf;
import ghidra.app.util.bin.BinaryReader;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import ghidra.app.util.bin.BinaryReader;
public class OmfExternalSymbol extends OmfRecord { public class OmfExternalSymbol extends OmfRecord {
private boolean isStatic; private boolean isStatic;
protected OmfSymbol[] symbol; protected OmfSymbol[] symbol;
protected OmfExternalSymbol(boolean isStatic) { protected OmfExternalSymbol(boolean isStatic) {
this.isStatic = isStatic; this.isStatic = isStatic;
} }
public OmfExternalSymbol(BinaryReader reader,boolean isStatic) throws IOException { public OmfExternalSymbol(BinaryReader reader, boolean isStatic) throws IOException {
this.isStatic = isStatic; this.isStatic = isStatic;
readRecordHeader(reader); readRecordHeader(reader);
long max = reader.getPointerIndex() + getRecordLength() - 1; long max = reader.getPointerIndex() + getRecordLength() - 1;
ArrayList<OmfSymbol> symbollist = new ArrayList<OmfSymbol>(); ArrayList<OmfSymbol> symbollist = new ArrayList<OmfSymbol>();
while(reader.getPointerIndex() < max) { while (reader.getPointerIndex() < max) {
String name = OmfRecord.readString(reader); String name = OmfRecord.readString(reader);
int type = OmfRecord.readIndex(reader); int type = OmfRecord.readIndex(reader);
OmfSymbol subrec = new OmfSymbol(name,type,0,0,0); OmfSymbol subrec = new OmfSymbol(name, type, 0, 0, 0);
symbollist.add(subrec); symbollist.add(subrec);
} }
readCheckSumByte(reader); readCheckSumByte(reader);
symbol = new OmfSymbol[symbollist.size()]; symbol = new OmfSymbol[symbollist.size()];
symbollist.toArray(symbol); symbollist.toArray(symbol);
@ -49,7 +49,7 @@ public class OmfExternalSymbol extends OmfRecord {
public OmfSymbol[] getSymbols() { public OmfSymbol[] getSymbols() {
return symbol; return symbol;
} }
public boolean isStatic() { public boolean isStatic() {
return isStatic; return isStatic;
} }

View file

@ -15,19 +15,19 @@
*/ */
package ghidra.app.util.bin.format.omf; package ghidra.app.util.bin.format.omf;
import java.util.ArrayList;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.ByteProvider; import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.importer.MessageLog;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
public class OmfFileHeader extends OmfRecord { public class OmfFileHeader extends OmfRecord {
private String objectName; // Name of the object module private String objectName; // Name of the object module
private String libModuleName=null; // Name of the module (within a library) private String libModuleName = null; // Name of the module (within a library)
private String translator=null; // Usually the compiler/linker used to produce this object private String translator = null; // Usually the compiler/linker used to produce this object
private boolean isLittleEndian; private boolean isLittleEndian;
private ArrayList<String> nameList = new ArrayList<String>(); // Indexable List of segment, group, ... names private ArrayList<String> nameList = new ArrayList<String>(); // Indexable List of segment, group, ... names
private ArrayList<OmfSegmentHeader> segments = new ArrayList<OmfSegmentHeader>(); private ArrayList<OmfSegmentHeader> segments = new ArrayList<OmfSegmentHeader>();
@ -36,7 +36,7 @@ public class OmfFileHeader extends OmfRecord {
private ArrayList<OmfSymbolRecord> symbols = new ArrayList<OmfSymbolRecord>(); private ArrayList<OmfSymbolRecord> symbols = new ArrayList<OmfSymbolRecord>();
private ArrayList<OmfFixupRecord> fixup = new ArrayList<OmfFixupRecord>(); private ArrayList<OmfFixupRecord> fixup = new ArrayList<OmfFixupRecord>();
private ArrayList<OmfSegmentHeader> extraSeg = null; // Holds implied segments that don't have official header record private ArrayList<OmfSegmentHeader> extraSeg = null; // Holds implied segments that don't have official header record
// private OmfModuleEnd endModule = null; // private OmfModuleEnd endModule = null;
public OmfFileHeader(BinaryReader reader) throws IOException { public OmfFileHeader(BinaryReader reader) throws IOException {
readRecordHeader(reader); readRecordHeader(reader);
@ -44,7 +44,7 @@ public class OmfFileHeader extends OmfRecord {
readCheckSumByte(reader); readCheckSumByte(reader);
isLittleEndian = reader.isLittleEndian(); isLittleEndian = reader.isLittleEndian();
} }
/** /**
* This is usually the original source filename * This is usually the original source filename
* @return the name * @return the name
@ -52,7 +52,7 @@ public class OmfFileHeader extends OmfRecord {
public String getName() { public String getName() {
return objectName; return objectName;
} }
/** /**
* The name of the object module (within a library) * The name of the object module (within a library)
* @return the name * @return the name
@ -60,14 +60,14 @@ public class OmfFileHeader extends OmfRecord {
public String getLibraryModuleName() { public String getLibraryModuleName() {
return libModuleName; return libModuleName;
} }
/** /**
* @return the string identifying the architecture this object was compiled for * @return the string identifying the architecture this object was compiled for
*/ */
public String getMachineName() { public String getMachineName() {
return "i386"; // This is the only possibility return "i386"; // This is the only possibility
} }
/** /**
* If the OMF file contains a "translator" record, this is usually a string * If the OMF file contains a "translator" record, this is usually a string
* indicating the compiler which produced the file. * indicating the compiler which produced the file.
@ -76,14 +76,14 @@ public class OmfFileHeader extends OmfRecord {
public String getTranslator() { public String getTranslator() {
return translator; return translator;
} }
/** /**
* @return true if the file describes the load image for a little endian architecture * @return true if the file describes the load image for a little endian architecture
*/ */
public boolean isLittleEndian() { public boolean isLittleEndian() {
return isLittleEndian; return isLittleEndian;
} }
/** /**
* @return the list of segments in this file * @return the list of segments in this file
*/ */
@ -97,7 +97,7 @@ public class OmfFileHeader extends OmfRecord {
public ArrayList<OmfSegmentHeader> getExtraSegments() { public ArrayList<OmfSegmentHeader> getExtraSegments() {
return extraSeg; return extraSeg;
} }
/** /**
* @return the list of group records for this file * @return the list of group records for this file
*/ */
@ -111,31 +111,31 @@ public class OmfFileHeader extends OmfRecord {
public ArrayList<OmfExternalSymbol> getExternalSymbols() { public ArrayList<OmfExternalSymbol> getExternalSymbols() {
return externsymbols; return externsymbols;
} }
/** /**
* @return the list of symbols exported by this file * @return the list of symbols exported by this file
*/ */
public ArrayList<OmfSymbolRecord> getPublicSymbols() { public ArrayList<OmfSymbolRecord> getPublicSymbols() {
return symbols; return symbols;
} }
/** /**
* @return the list of relocation records for this file * @return the list of relocation records for this file
*/ */
public ArrayList<OmfFixupRecord> getFixups() { public ArrayList<OmfFixupRecord> getFixups() {
return fixup; return fixup;
} }
/** /**
* Sort the explicit data-blocks for each segment into address order. * Sort the explicit data-blocks for each segment into address order.
*/ */
public void sortSegmentDataBlocks() { public void sortSegmentDataBlocks() {
if (extraSeg != null) { if (extraSeg != null) {
for(int i=0;i<extraSeg.size();++i) { for (int i = 0; i < extraSeg.size(); ++i) {
segments.add(extraSeg.get(i)); segments.add(extraSeg.get(i));
} }
} }
for(int i=0;i<segments.size();++i) { for (int i = 0; i < segments.size(); ++i) {
segments.get(i).sortData(); segments.get(i).sortData();
} }
} }
@ -149,16 +149,16 @@ public class OmfFileHeader extends OmfRecord {
int index = datablock.getSegmentIndex(); int index = datablock.getSegmentIndex();
int subindex = -1; int subindex = -1;
OmfSegmentHeader segment; OmfSegmentHeader segment;
if ((index & 0x4000)!=0) { if ((index & 0x4000) != 0) {
subindex = index & 0x3fff; subindex = index & 0x3fff;
index = 1; index = 1;
segment = createOrFindBorlandSegment(subindex, 1); segment = createOrFindBorlandSegment(subindex, 1);
} }
else { else {
if ((index <=0)||(index>segments.size())) { if ((index <= 0) || (index > segments.size())) {
throw new OmfException("Bad segment index"); throw new OmfException("Bad segment index");
} }
segment = segments.get(index-1); segment = segments.get(index - 1);
} }
if (subindex != -1) { if (subindex != -1) {
segment.appendEnumeratedData(datablock); segment.appendEnumeratedData(datablock);
@ -167,7 +167,7 @@ public class OmfFileHeader extends OmfRecord {
segment.addEnumeratedData(datablock); segment.addEnumeratedData(datablock);
} }
} }
/** /**
* Given an index, retrieve the specific segment it refers to. This * Given an index, retrieve the specific segment it refers to. This
* incorporates the special Borland segments, where the index has * incorporates the special Borland segments, where the index has
@ -179,21 +179,21 @@ public class OmfFileHeader extends OmfRecord {
public OmfSegmentHeader resolveSegment(int index) throws OmfException { public OmfSegmentHeader resolveSegment(int index) throws OmfException {
int subindex = -1; int subindex = -1;
OmfSegmentHeader res; OmfSegmentHeader res;
if ((index & 0x4000)!=0) { if ((index & 0x4000) != 0) {
subindex = index & 0x3fff; subindex = index & 0x3fff;
if ((subindex<=0)||(subindex>extraSeg.size())) { if ((subindex <= 0) || (subindex > extraSeg.size())) {
throw new OmfException("Bad extra segment index"); throw new OmfException("Bad extra segment index");
} }
res = extraSeg.get(subindex - 1); res = extraSeg.get(subindex - 1);
return res; return res;
} }
if ((index <=0)||(index>segments.size())) { if ((index <= 0) || (index > segments.size())) {
throw new OmfException("Bad segment index"); throw new OmfException("Bad segment index");
} }
res = segments.get(index-1); res = segments.get(index - 1);
return res; return res;
} }
/** /**
* Resolve special names associated with each segment: segment, class, overlay names * Resolve special names associated with each segment: segment, class, overlay names
* and group: group name * and group: group name
@ -201,15 +201,15 @@ public class OmfFileHeader extends OmfRecord {
* @throws OmfException if any name indices are malformed * @throws OmfException if any name indices are malformed
*/ */
public void resolveNames() throws OmfException { public void resolveNames() throws OmfException {
for(int i=0;i<segments.size();++i) { for (int i = 0; i < segments.size(); ++i) {
segments.get(i).resolveNames(nameList); segments.get(i).resolveNames(nameList);
} }
// extraSeg segments already have names // extraSeg segments already have names
for(int i=0;i<groups.size();++i) { for (int i = 0; i < groups.size(); ++i) {
groups.get(i).resolveNames(nameList); groups.get(i).resolveNames(nameList);
} }
} }
/** /**
* Given an index, either find an existing Borland segment, or create a new one. * Given an index, either find an existing Borland segment, or create a new one.
* Borland compilers can introduce special segments with a separate indexing * Borland compilers can introduce special segments with a separate indexing
@ -219,30 +219,30 @@ public class OmfFileHeader extends OmfRecord {
* @param datatype is the type of (new) segment * @param datatype is the type of (new) segment
* @return the corresponding OmfSegmentHeader * @return the corresponding OmfSegmentHeader
*/ */
private OmfSegmentHeader createOrFindBorlandSegment(int index,int datatype) { private OmfSegmentHeader createOrFindBorlandSegment(int index, int datatype) {
if (extraSeg == null) { if (extraSeg == null) {
extraSeg = new ArrayList<OmfSegmentHeader>(); extraSeg = new ArrayList<OmfSegmentHeader>();
} }
while(extraSeg.size() < index) { while (extraSeg.size() < index) {
extraSeg.add(null); extraSeg.add(null);
} }
OmfSegmentHeader segment = extraSeg.get(index-1); OmfSegmentHeader segment = extraSeg.get(index - 1);
if (segment == null) { if (segment == null) {
segment = new OmfSegmentHeader(index,datatype); segment = new OmfSegmentHeader(index, datatype);
extraSeg.set(index-1,segment); extraSeg.set(index - 1, segment);
} }
return segment; return segment;
} }
private void evaluateComdef(OmfComdefRecord comdef) { private void evaluateComdef(OmfComdefRecord comdef) {
OmfSymbol[] coms = comdef.getSymbols(); OmfSymbol[] coms = comdef.getSymbols();
for (OmfSymbol sym : coms) { for (OmfSymbol sym : coms) {
int dt = sym.getDataType(); int dt = sym.getDataType();
if (dt >0 && dt < 0x60) { // A special borland segment symbol if (dt > 0 && dt < 0x60) { // A special borland segment symbol
int count = (extraSeg==null) ? 1 : extraSeg.size()+1; int count = (extraSeg == null) ? 1 : extraSeg.size() + 1;
createOrFindBorlandSegment(count,dt); createOrFindBorlandSegment(count, dt);
sym.setSegmentRef(count); sym.setSegmentRef(count);
} }
} }
} }
@ -256,128 +256,127 @@ public class OmfFileHeader extends OmfRecord {
* @throws IOException for problems reading program data * @throws IOException for problems reading program data
* @throws OmfException for malformed records * @throws OmfException for malformed records
*/ */
public static OmfFileHeader scan(BinaryReader reader,TaskMonitor monitor,boolean initialCommentsOnly) throws IOException, OmfException { public static OmfFileHeader scan(BinaryReader reader, TaskMonitor monitor,
boolean initialCommentsOnly) throws IOException, OmfException {
OmfRecord record = OmfRecord.readRecord(reader); OmfRecord record = OmfRecord.readRecord(reader);
if ((record.getRecordType() & (byte)0xfc)!=OmfRecord.THEADR) { if (!(record instanceof OmfFileHeader)) {
throw new OmfException("Object file does not start with proper header"); throw new OmfException("Object file does not start with proper header");
} }
OmfFileHeader header = (OmfFileHeader)record; OmfFileHeader header = (OmfFileHeader) record;
byte type = record.getRecordType();
type &= 0xfe; while (true) {
while(type != MODEND) {
if (monitor.isCancelled()) {
break; // Return what we have
}
record = OmfRecord.readRecord(reader); record = OmfRecord.readRecord(reader);
type = record.getRecordType();
type &= 0xfe; // Mask off the least significant bit if (monitor.isCancelled()) {
if (initialCommentsOnly && (type != COMENT)) {
break; break;
} }
switch(type) { if (record instanceof OmfModuleEnd) {
case COMENT: break;
byte commentClass = ((OmfCommentRecord)record).getCommentClass(); }
if (record instanceof OmfCommentRecord comment) {
byte commentClass = comment.getCommentClass();
if (commentClass == OmfCommentRecord.COMMENT_CLASS_TRANSLATOR) { if (commentClass == OmfCommentRecord.COMMENT_CLASS_TRANSLATOR) {
header.translator = ((OmfCommentRecord)record).getValue(); header.translator = comment.getValue();
} }
else if (commentClass == OmfCommentRecord.COMMENT_CLASS_LIBMOD) { else if (commentClass == OmfCommentRecord.COMMENT_CLASS_LIBMOD) {
header.libModuleName = ((OmfCommentRecord)record).getValue(); header.libModuleName = comment.getValue();
} }
}
else if (initialCommentsOnly) {
break; break;
default:
break; // Skip most records
} }
} }
return header; return header;
} }
/** /**
* Parse the entire object file * Parse the entire object file
*
* @param reader is the byte stream * @param reader is the byte stream
* @param monitor is checked for cancel button * @param monitor is checked for cancel button
* @param log the log
* @return the header record as root of object * @return the header record as root of object
* @throws IOException for problems reading data * @throws IOException for problems reading data
* @throws OmfException for malformed records * @throws OmfException for malformed records
*/ */
public static OmfFileHeader parse(BinaryReader reader,TaskMonitor monitor) throws IOException, OmfException { public static OmfFileHeader parse(BinaryReader reader, TaskMonitor monitor, MessageLog log)
throws IOException, OmfException {
OmfRecord record = OmfRecord.readRecord(reader); OmfRecord record = OmfRecord.readRecord(reader);
if ((record.getRecordType() & (byte)0xfc)!=OmfRecord.THEADR) { if (!(record instanceof OmfFileHeader)) {
throw new OmfException("Object file does not start with proper header"); throw new OmfException("Object file does not start with proper header");
} }
OmfFileHeader header = (OmfFileHeader)record; OmfFileHeader header = (OmfFileHeader) record;
Object lastDataBlock = null; Object lastDataBlock = null;
while((record.getRecordType() & (byte)0xfe) != OmfRecord.MODEND) { while (true) {
if (monitor.isCancelled()) {
break; // Return what we have
}
record = OmfRecord.readRecord(reader); record = OmfRecord.readRecord(reader);
byte type = record.getRecordType();
type &= 0xfe; // Mask off the least significant bit if (monitor.isCancelled()) {
switch(type) { break;
case COMENT: }
byte commentClass = ((OmfCommentRecord)record).getCommentClass(); if (record instanceof OmfModuleEnd) {
break;
}
if (record instanceof OmfCommentRecord comment) {
byte commentClass = comment.getCommentClass();
if (commentClass == OmfCommentRecord.COMMENT_CLASS_TRANSLATOR) { if (commentClass == OmfCommentRecord.COMMENT_CLASS_TRANSLATOR) {
header.translator = ((OmfCommentRecord)record).getValue(); header.translator = comment.getValue();
} }
else if (commentClass == OmfCommentRecord.COMMENT_CLASS_LIBMOD) { else if (commentClass == OmfCommentRecord.COMMENT_CLASS_LIBMOD) {
header.libModuleName = ((OmfCommentRecord)record).getValue(); header.libModuleName = comment.getValue();
} }
break; }
case MODEND: else if (record instanceof OmfComdefRecord comdef) {
// header.endModule = (OmfModuleEnd)record; header.evaluateComdef(comdef);
// We are not currently examining the end module record header.externsymbols.add((OmfExternalSymbol) record);
break; }
case COMDEF: else if (record instanceof OmfExternalSymbol external) {
case LCOMDEF: header.externsymbols.add(external);
header.evaluateComdef((OmfComdefRecord)record); }
header.externsymbols.add((OmfExternalSymbol)record); else if (record instanceof OmfSymbolRecord symbol) {
break; header.symbols.add(symbol);
case LEXTDEF: }
case EXTDEF: else if (record instanceof OmfNamesRecord names) {
header.externsymbols.add((OmfExternalSymbol)record); names.appendNames(header.nameList); // Keep names, otherwise don't save record
break; }
case PUBDEF: else if (record instanceof OmfSegmentHeader seghead) {
case LPUBDEF: header.segments.add(seghead);
header.symbols.add((OmfSymbolRecord)record); }
break; else if (record instanceof OmfGroupRecord group) {
case LINNUM: header.groups.add(group);
break; // Not saving this information currently }
case LNAMES: else if (record instanceof OmfFixupRecord fixuprec) {
((OmfNamesRecord)record).appendNames(header.nameList); // Keep names, otherwise don't save record
break;
case SEGDEF:
header.segments.add((OmfSegmentHeader)record);
break;
case GRPDEF:
header.groups.add((OmfGroupRecord)record);
break;
case FIXUPP:
OmfFixupRecord fixuprec = (OmfFixupRecord)record;
fixuprec.setDataBlock(lastDataBlock); fixuprec.setDataBlock(lastDataBlock);
header.fixup.add(fixuprec); header.fixup.add(fixuprec);
break; }
case LEDATA: else if (record instanceof OmfEnumeratedData enumheader) {
OmfEnumeratedData enumheader = (OmfEnumeratedData)record;
header.addEnumeratedBlock(enumheader); header.addEnumeratedBlock(enumheader);
lastDataBlock = enumheader; lastDataBlock = enumheader;
break; }
case LIDATA: else if (record instanceof OmfIteratedData iterheader) {
OmfIteratedData iterheader = (OmfIteratedData)record; if (iterheader.getSegmentIndex() <= 0 ||
if (iterheader.getSegmentIndex() <= 0 || iterheader.getSegmentIndex() > header.segments.size()) { iterheader.getSegmentIndex() > header.segments.size()) {
throw new OmfException("Bad segment index on LIDATA"); throw new OmfException("Bad segment index on LIDATA");
} }
OmfSegmentHeader segheader2 = header.segments.get(iterheader.getSegmentIndex()-1); OmfSegmentHeader segheader2 = header.segments.get(iterheader.getSegmentIndex() - 1);
segheader2.addIteratedData(iterheader); segheader2.addIteratedData(iterheader);
lastDataBlock = iterheader; lastDataBlock = iterheader;
break; }
default: else if (record instanceof OmfUnsupportedRecord) {
// Should never reach here logRecord("Unsupported OMF record", record, log);
}
else if (record instanceof OmfObsoleteRecord) {
logRecord("Obsolete OMF record", record, log);
}
else if (record instanceof OmfUnknownRecord) {
logRecord("Unknown OMF record", record, log);
} }
} }
return header; return header;
} }
/** /**
* Assign a load image address to each segment. Follow OMF rules for grouping and ordering * Assign a load image address to each segment. Follow OMF rules for grouping and ordering
* the segments in memory. * the segments in memory.
@ -386,7 +385,8 @@ public class OmfFileHeader extends OmfRecord {
* @param groups is the list of specific segments that are grouped together in memory * @param groups is the list of specific segments that are grouped together in memory
* @throws OmfException for malformed index/alignment/combining fields * @throws OmfException for malformed index/alignment/combining fields
*/ */
public static void doLinking(long startAddress,ArrayList<OmfSegmentHeader> segments,ArrayList<OmfGroupRecord> groups) throws OmfException { public static void doLinking(long startAddress, ArrayList<OmfSegmentHeader> segments,
ArrayList<OmfGroupRecord> groups) throws OmfException {
// Link anything in groups first // Link anything in groups first
for (int i = 0; i < groups.size(); ++i) { for (int i = 0; i < groups.size(); ++i) {
OmfGroupRecord group = groups.get(i); OmfGroupRecord group = groups.get(i);
@ -396,14 +396,15 @@ public class OmfFileHeader extends OmfRecord {
try { try {
OmfSegmentHeader segment = segments.get(index - 1); OmfSegmentHeader segment = segments.get(index - 1);
startAddress = segment.relocateSegment(startAddress, -1); startAddress = segment.relocateSegment(startAddress, -1);
} catch (IndexOutOfBoundsException ex) { }
catch (IndexOutOfBoundsException ex) {
throw new OmfException(ex.getMessage()); throw new OmfException(ex.getMessage());
} }
} }
} }
// Fill in any remaining segments // Fill in any remaining segments
for(int i=0;i<segments.size();++i) { for (int i = 0; i < segments.size(); ++i) {
OmfSegmentHeader segment = segments.get(i); OmfSegmentHeader segment = segments.get(i);
if (segment.getStartAddress() != -1) { if (segment.getStartAddress() != -1) {
continue; // Address already assigned continue; // Address already assigned
@ -411,7 +412,7 @@ public class OmfFileHeader extends OmfRecord {
startAddress = segment.relocateSegment(startAddress, -1); startAddress = segment.relocateSegment(startAddress, -1);
// Look for any segments with same name,class which should be officially "combined" with this segment // Look for any segments with same name,class which should be officially "combined" with this segment
for(int j=i+1;j<segments.size();++j) { for (int j = i + 1; j < segments.size(); ++j) {
OmfSegmentHeader combineSeg = segments.get(j); OmfSegmentHeader combineSeg = segments.get(j);
if (combineSeg.getStartAddress() != -1) { if (combineSeg.getStartAddress() != -1) {
continue; continue;
@ -426,19 +427,19 @@ public class OmfFileHeader extends OmfRecord {
if (C == 0) { if (C == 0) {
continue; // Private segment continue; // Private segment
} }
if (C==2 || C==4 || C==7) { if (C == 2 || C == 4 || C == 7) {
startAddress = combineSeg.relocateSegment(startAddress, -1); startAddress = combineSeg.relocateSegment(startAddress, -1);
} }
else if (C==5) { else if (C == 5) {
startAddress = combineSeg.relocateSegment(startAddress, 1); startAddress = combineSeg.relocateSegment(startAddress, 1);
} }
else { else {
throw new OmfException("Combine type not supported"); throw new OmfException("Combine type not supported");
} }
} }
} }
} }
/** /**
* Check that the file has the specific OMF magic number * Check that the file has the specific OMF magic number
* @param reader accesses the bytes of the file * @param reader accesses the bytes of the file
@ -457,13 +458,17 @@ public class OmfFileHeader extends OmfRecord {
} }
return true; return true;
} }
/** /**
* Create a reader for a specific OMF file * Create a reader for a specific OMF file
* @param provider is the underlying ByteProvider * @param provider is the underlying ByteProvider
* @return the new reader * @return the new reader
*/ */
public static BinaryReader createReader(ByteProvider provider) { public static BinaryReader createReader(ByteProvider provider) {
return new BinaryReader(provider,true/* Always little endian */); return new BinaryReader(provider, true/* Always little endian */);
}
private static void logRecord(String description, OmfRecord record, MessageLog log) {
log.appendMsg(description + " (" + record + ")");
} }
} }

View file

@ -27,16 +27,16 @@ public class OmfFixupRecord extends OmfRecord {
private Subrecord[] subrecs; private Subrecord[] subrecs;
private OmfEnumeratedData lastLEData = null; private OmfEnumeratedData lastLEData = null;
private OmfIteratedData lastLIData = null; private OmfIteratedData lastLIData = null;
public OmfFixupRecord(BinaryReader reader) throws IOException { public OmfFixupRecord(BinaryReader reader) throws IOException {
ArrayList<Subrecord> subreclist = new ArrayList<Subrecord>(); ArrayList<Subrecord> subreclist = new ArrayList<Subrecord>();
boolean hasBigFields = ((getRecordType() & 1)!=0); boolean hasBigFields = ((getRecordType() & 1) != 0);
readRecordHeader(reader); readRecordHeader(reader);
long max = reader.getPointerIndex() + getRecordLength() - 1; long max = reader.getPointerIndex() + getRecordLength() - 1;
while(reader.getPointerIndex() < max) { while (reader.getPointerIndex() < max) {
byte peek = reader.peekNextByte(); byte peek = reader.peekNextByte();
if ((peek & 0x80)==0) { if ((peek & 0x80) == 0) {
ThreadSubrecord subrec = ThreadSubrecord.readThreadSubrecord(reader, hasBigFields); ThreadSubrecord subrec = ThreadSubrecord.readThreadSubrecord(reader, hasBigFields);
subreclist.add(subrec); subreclist.add(subrec);
} }
@ -49,18 +49,18 @@ public class OmfFixupRecord extends OmfRecord {
subreclist.toArray(subrecs); subreclist.toArray(subrecs);
readCheckSumByte(reader); readCheckSumByte(reader);
} }
public void setDataBlock(Object last) { public void setDataBlock(Object last) {
if (last instanceof OmfEnumeratedData) { if (last instanceof OmfEnumeratedData) {
lastLEData = (OmfEnumeratedData)last; lastLEData = (OmfEnumeratedData) last;
lastLIData = null; lastLIData = null;
} }
else { else {
lastLIData = (OmfIteratedData)last; lastLIData = (OmfIteratedData) last;
lastLEData = null; lastLEData = null;
} }
} }
public Subrecord[] getSubrecords() { public Subrecord[] getSubrecords() {
return subrecs; return subrecs;
} }
@ -78,9 +78,9 @@ public class OmfFixupRecord extends OmfRecord {
public Address locAddress; // Location of data to be patched public Address locAddress; // Location of data to be patched
public boolean M; // true for segment-relative, false for self-relative public boolean M; // true for segment-relative, false for self-relative
public int locationType; public int locationType;
public FixupState(OmfFileHeader header,ArrayList<OmfSymbol> externsyms,Language lang) { public FixupState(OmfFileHeader header, ArrayList<OmfSymbol> externsyms, Language lang) {
for(int i=0;i<4;++i) { for (int i = 0; i < 4; ++i) {
frameThreads[i] = null; frameThreads[i] = null;
targetThreads[i] = null; targetThreads[i] = null;
} }
@ -89,26 +89,26 @@ public class OmfFixupRecord extends OmfRecord {
externals = externsyms; externals = externsyms;
language = lang; language = lang;
} }
public void clear() { public void clear() {
targetState = -1; targetState = -1;
locAddress = null; locAddress = null;
locationType = -1; locationType = -1;
} }
} }
public static class Subrecord { public static class Subrecord {
private boolean isThread; private boolean isThread;
public Subrecord(boolean isthread) { public Subrecord(boolean isthread) {
isThread = isthread; isThread = isthread;
} }
public boolean isThread() { public boolean isThread() {
return isThread; return isThread;
} }
} }
public static class ThreadSubrecord extends Subrecord { public static class ThreadSubrecord extends Subrecord {
private byte type; private byte type;
private int index; private int index;
@ -116,42 +116,47 @@ public class OmfFixupRecord extends OmfRecord {
public ThreadSubrecord() { public ThreadSubrecord() {
super(true); super(true);
} }
public int getMethod() { public int getMethod() {
return (type>>2) & 7; return (type >> 2) & 7;
} }
public int getIndex() { public int getIndex() {
return index; return index;
} }
public boolean isFrameThread() { public boolean isFrameThread() {
return ((type>>6)&1)!=0; return ((type >> 6) & 1) != 0;
} }
public int getThreadNum() { public int getThreadNum() {
return (type & 3); return (type & 3);
} }
public void updateState(FixupState state) { public void updateState(FixupState state) {
if (isFrameThread()) if (isFrameThread()) {
state.frameThreads[getThreadNum()] = this; state.frameThreads[getThreadNum()] = this;
else }
else {
state.targetThreads[getThreadNum()] = this; state.targetThreads[getThreadNum()] = this;
}
} }
public static ThreadSubrecord readThreadSubrecord(BinaryReader reader,boolean hasBigFields) throws IOException { public static ThreadSubrecord readThreadSubrecord(BinaryReader reader, boolean hasBigFields)
throws IOException {
ThreadSubrecord thread = new ThreadSubrecord(); ThreadSubrecord thread = new ThreadSubrecord();
thread.type = reader.readNextByte(); thread.type = reader.readNextByte();
int method = thread.getMethod(); int method = thread.getMethod();
if (method < 4) if (method < 4) {
thread.index = OmfRecord.readInt1Or2(reader, hasBigFields); thread.index = OmfRecord.readInt1Or2(reader, hasBigFields);
else }
else {
thread.index = -1; thread.index = -1;
}
return thread; return thread;
} }
} }
public static class FixupTarget { public static class FixupTarget {
private byte fixData; private byte fixData;
private int frameDatum; private int frameDatum;
@ -159,28 +164,28 @@ public class OmfFixupRecord extends OmfRecord {
private int targetDisplacement; private int targetDisplacement;
public boolean isFrameThread() { public boolean isFrameThread() {
return ((fixData>>7)&1)!=0; return ((fixData >> 7) & 1) != 0;
} }
public boolean isTargetThread() { public boolean isTargetThread() {
return ((fixData>>3)&1)!=0; return ((fixData >> 3) & 1) != 0;
} }
public int getFrameMethod() { public int getFrameMethod() {
return ((fixData>>4)&7); return ((fixData >> 4) & 7);
} }
public int getP() { public int getP() {
int res = (fixData >>2)&1; int res = (fixData >> 2) & 1;
return res; return res;
} }
public void resolveFrame(FixupState state) throws OmfException { public void resolveFrame(FixupState state) throws OmfException {
int method; int method;
int index; int index;
if (isFrameThread()) { if (isFrameThread()) {
// Frame datum from a thread // Frame datum from a thread
int threadnum = ((fixData>>4)&3); int threadnum = ((fixData >> 4) & 3);
ThreadSubrecord subrec = state.frameThreads[threadnum]; ThreadSubrecord subrec = state.frameThreads[threadnum];
method = subrec.getMethod(); method = subrec.getMethod();
index = subrec.getIndex(); index = subrec.getIndex();
@ -189,31 +194,33 @@ public class OmfFixupRecord extends OmfRecord {
method = getFrameMethod(); method = getFrameMethod();
index = frameDatum; index = frameDatum;
} }
switch(method) { switch (method) {
case 0: // Index is for a segment case 0: // Index is for a segment
state.frameState = state.header.resolveSegment(index).getFrameDatum(); state.frameState = state.header.resolveSegment(index).getFrameDatum();
break; break;
case 1: // Index is for a group case 1: // Index is for a group
state.frameState = state.groups.get(index-1).getFrameDatum(); state.frameState = state.groups.get(index - 1).getFrameDatum();
break; break;
case 2: // Index is for an external symbol case 2: // Index is for an external symbol
state.frameState = state.externals.get(index-1).getFrameDatum(); state.frameState = state.externals.get(index - 1).getFrameDatum();
break; break;
case 4: // Segment Index grabbed from datablock case 4: // Segment Index grabbed from datablock
if (state.currentFixupRecord.lastLEData != null) if (state.currentFixupRecord.lastLEData != null) {
index = state.currentFixupRecord.lastLEData.getSegmentIndex(); index = state.currentFixupRecord.lastLEData.getSegmentIndex();
else }
index = state.currentFixupRecord.lastLIData.getSegmentIndex(); else {
state.frameState = state.header.resolveSegment(index).getFrameDatum(); index = state.currentFixupRecord.lastLIData.getSegmentIndex();
break; }
case 5: // Frame determined by target state.frameState = state.header.resolveSegment(index).getFrameDatum();
// TODO: Fill this in properly break;
break; case 5: // Frame determined by target
default: // TODO: Fill this in properly
state.frameState = -1; // Indicate an error condition break;
default:
state.frameState = -1; // Indicate an error condition
} }
} }
public void resolveTarget(FixupState state) throws OmfException { public void resolveTarget(FixupState state) throws OmfException {
int method; int method;
int index; int index;
@ -230,67 +237,68 @@ public class OmfFixupRecord extends OmfRecord {
index = targetDatum; index = targetDatum;
} }
switch(method) { switch (method) {
case 0: // Index is for a segment case 0: // Index is for a segment
state.targetState = state.header.resolveSegment(index).getStartAddress(); state.targetState = state.header.resolveSegment(index).getStartAddress();
state.targetState += targetDisplacement; state.targetState += targetDisplacement;
break; break;
case 1: // Index is for a group case 1: // Index is for a group
state.targetState = state.groups.get(index-1).getStartAddress(); state.targetState = state.groups.get(index - 1).getStartAddress();
state.targetState += targetDisplacement; state.targetState += targetDisplacement;
break; break;
case 2: // Index is for an external symbol case 2: // Index is for an external symbol
state.targetState = state.externals.get(index-1).getAddress().getOffset(); state.targetState = state.externals.get(index - 1).getAddress().getOffset();
state.targetState += targetDisplacement; state.targetState += targetDisplacement;
break; break;
// case 3: // Not supported by many linkers // case 3: // Not supported by many linkers
case 4: // segment only, no displacement case 4: // segment only, no displacement
state.targetState = state.header.resolveSegment(index).getStartAddress(); state.targetState = state.header.resolveSegment(index).getStartAddress();
break; break;
case 5: // group only, no displacement case 5: // group only, no displacement
state.targetState = state.groups.get(index-1).getStartAddress(); state.targetState = state.groups.get(index - 1).getStartAddress();
break; break;
case 6: // external only, no displacement case 6: // external only, no displacement
state.targetState = state.externals.get(index-1).getAddress().getOffset(); state.targetState = state.externals.get(index - 1).getAddress().getOffset();
break; break;
default: default:
state.targetState = -1; // This indicates an unresolved target state.targetState = -1; // This indicates an unresolved target
} }
} }
public static FixupTarget readFixupTarget(BinaryReader reader,boolean hasBigFields) throws IOException { public static FixupTarget readFixupTarget(BinaryReader reader, boolean hasBigFields)
throws IOException {
FixupTarget fixupTarget = new FixupTarget(); FixupTarget fixupTarget = new FixupTarget();
fixupTarget.fixData = reader.readNextByte(); fixupTarget.fixData = reader.readNextByte();
if ((fixupTarget.fixData & 0x80)==0) { // F=0 (explicit frame method (and datum)) if ((fixupTarget.fixData & 0x80) == 0) { // F=0 (explicit frame method (and datum))
int method = (fixupTarget.fixData >> 4)&7; int method = (fixupTarget.fixData >> 4) & 7;
if (method <3) { if (method < 3) {
fixupTarget.frameDatum = OmfRecord.readIndex(reader); fixupTarget.frameDatum = OmfRecord.readIndex(reader);
} }
} }
if ((fixupTarget.fixData & 0x08)==0) { // T=0 (explicit target) if ((fixupTarget.fixData & 0x08) == 0) { // T=0 (explicit target)
fixupTarget.targetDatum = OmfRecord.readIndex(reader); fixupTarget.targetDatum = OmfRecord.readIndex(reader);
} }
if ((fixupTarget.fixData & 0x04)==0) // P=0 if ((fixupTarget.fixData & 0x04) == 0) // P=0
fixupTarget.targetDisplacement = OmfRecord.readInt2Or4(reader, hasBigFields); fixupTarget.targetDisplacement = OmfRecord.readInt2Or4(reader, hasBigFields);
return fixupTarget; return fixupTarget;
} }
} }
public static class FixupSubrecord extends Subrecord { public static class FixupSubrecord extends Subrecord {
private byte lobyte; // lo-byte of location private byte lobyte; // lo-byte of location
private byte hibyte; // hi-byte of location private byte hibyte; // hi-byte of location
private FixupTarget target; private FixupTarget target;
public FixupSubrecord() { public FixupSubrecord() {
super(false); super(false);
} }
public void resolveFixup(FixupState state) throws OmfException { public void resolveFixup(FixupState state) throws OmfException {
target.resolveTarget(state); // Resolve target first as frame may need to reference results target.resolveTarget(state); // Resolve target first as frame may need to reference results
target.resolveFrame(state); target.resolveFrame(state);
state.M = ((lobyte>>6)&1)!=0; state.M = ((lobyte >> 6) & 1) != 0;
state.locationType = ((lobyte>>2)&0xf); state.locationType = ((lobyte >> 2) & 0xf);
int dataRecordOffset = lobyte & 3; int dataRecordOffset = lobyte & 3;
dataRecordOffset <<= 8; dataRecordOffset <<= 8;
dataRecordOffset |= (hibyte) & 0xff; dataRecordOffset |= (hibyte) & 0xff;
@ -305,15 +313,16 @@ public class OmfFixupRecord extends OmfRecord {
segIndex = state.currentFixupRecord.lastLIData.getSegmentIndex(); segIndex = state.currentFixupRecord.lastLIData.getSegmentIndex();
} }
OmfSegmentHeader seg = state.header.resolveSegment(segIndex); OmfSegmentHeader seg = state.header.resolveSegment(segIndex);
state.locAddress = seg.getAddress(state.language).add(blockDisplace + dataRecordOffset); state.locAddress = seg.getAddress(state.language).add(blockDisplace + dataRecordOffset);
} }
public static FixupSubrecord readFixupSubrecord(BinaryReader reader,boolean hasBigFields) throws IOException { public static FixupSubrecord readFixupSubrecord(BinaryReader reader, boolean hasBigFields)
throws IOException {
FixupSubrecord fixupSubrecord = new FixupSubrecord(); FixupSubrecord fixupSubrecord = new FixupSubrecord();
fixupSubrecord.lobyte = reader.readNextByte(); fixupSubrecord.lobyte = reader.readNextByte();
fixupSubrecord.hibyte = reader.readNextByte(); fixupSubrecord.hibyte = reader.readNextByte();
fixupSubrecord.target = FixupTarget.readFixupTarget(reader, hasBigFields); fixupSubrecord.target = FixupTarget.readFixupTarget(reader, hasBigFields);
return fixupSubrecord; return fixupSubrecord;
} }
} }
} }

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -29,21 +28,21 @@ public class OmfGroupRecord extends OmfRecord {
private String groupName; private String groupName;
private long vma = -1; // Assigned (by linker) starting address of the whole group private long vma = -1; // Assigned (by linker) starting address of the whole group
private GroupSubrecord[] group; private GroupSubrecord[] group;
public OmfGroupRecord(BinaryReader reader) throws IOException { public OmfGroupRecord(BinaryReader reader) throws IOException {
readRecordHeader(reader); readRecordHeader(reader);
long max = reader.getPointerIndex() + getRecordLength() - 1; long max = reader.getPointerIndex() + getRecordLength() - 1;
groupNameIndex = OmfRecord.readIndex(reader); groupNameIndex = OmfRecord.readIndex(reader);
ArrayList<GroupSubrecord> grouplist = new ArrayList<GroupSubrecord>(); ArrayList<GroupSubrecord> grouplist = new ArrayList<GroupSubrecord>();
while(reader.getPointerIndex() < max) { while (reader.getPointerIndex() < max) {
GroupSubrecord subrec = GroupSubrecord.read(reader); GroupSubrecord subrec = GroupSubrecord.read(reader);
grouplist.add(subrec); grouplist.add(subrec);
} }
readCheckSumByte(reader); readCheckSumByte(reader);
group = new GroupSubrecord[ grouplist.size() ]; group = new GroupSubrecord[grouplist.size()];
grouplist.toArray(group); grouplist.toArray(group);
} }
public String getName() { public String getName() {
return groupName; return groupName;
} }
@ -51,48 +50,50 @@ public class OmfGroupRecord extends OmfRecord {
public void setStartAddress(long val) { public void setStartAddress(long val) {
vma = val; vma = val;
} }
public long getStartAddress() { public long getStartAddress() {
return vma; return vma;
} }
/** /**
* This is the segment selector needed for this object * This is the segment selector needed for this object
* @return * @return The segment selector
*/ */
public int getFrameDatum() { public int getFrameDatum() {
return 0; // TODO: Need to fill in a real segment selector return 0; // TODO: Need to fill in a real segment selector
} }
public int numSegments() { public int numSegments() {
return group.length; return group.length;
} }
public byte getSegmentComponentType(int i) { public byte getSegmentComponentType(int i) {
return group[i].componentType; return group[i].componentType;
} }
public int getSegmentIndex(int i) { public int getSegmentIndex(int i) {
return group[i].segmentIndex; return group[i].segmentIndex;
} }
public Address getAddress(Language language) { public Address getAddress(Language language) {
AddressSpace addrSpace = language.getDefaultSpace(); AddressSpace addrSpace = language.getDefaultSpace();
return addrSpace.getAddress(vma); return addrSpace.getAddress(vma);
} }
public void resolveNames(ArrayList<String> nameList) throws OmfException { public void resolveNames(ArrayList<String> nameList) throws OmfException {
if (groupNameIndex <= 0) if (groupNameIndex <= 0) {
throw new OmfException("Cannot have unused group name"); throw new OmfException("Cannot have unused group name");
if (groupNameIndex > nameList.size()) }
if (groupNameIndex > nameList.size()) {
throw new OmfException("Group name index out of bounds"); throw new OmfException("Group name index out of bounds");
}
groupName = nameList.get(groupNameIndex - 1); groupName = nameList.get(groupNameIndex - 1);
} }
public static class GroupSubrecord { public static class GroupSubrecord {
private byte componentType; private byte componentType;
private int segmentIndex; private int segmentIndex;
public static GroupSubrecord read(BinaryReader reader) throws IOException { public static GroupSubrecord read(BinaryReader reader) throws IOException {
GroupSubrecord subrec = new GroupSubrecord(); GroupSubrecord subrec = new GroupSubrecord();
subrec.componentType = reader.readNextByte(); subrec.componentType = reader.readNextByte();

View file

@ -34,7 +34,7 @@ public class OmfIteratedData extends OmfRecord implements OmfData {
segmentIndex = OmfRecord.readIndex(reader); segmentIndex = OmfRecord.readIndex(reader);
dataOffset = OmfRecord.readInt2Or4(reader, hasBigFields); dataOffset = OmfRecord.readInt2Or4(reader, hasBigFields);
ArrayList<DataBlock> blocklist = new ArrayList<DataBlock>(); ArrayList<DataBlock> blocklist = new ArrayList<DataBlock>();
while(reader.getPointerIndex() < max) { while (reader.getPointerIndex() < max) {
DataBlock block = DataBlock.read(reader, hasBigFields); DataBlock block = DataBlock.read(reader, hasBigFields);
blocklist.add(block); blocklist.add(block);
} }
@ -42,7 +42,7 @@ public class OmfIteratedData extends OmfRecord implements OmfData {
datablock = new DataBlock[blocklist.size()]; datablock = new DataBlock[blocklist.size()];
blocklist.toArray(datablock); blocklist.toArray(datablock);
} }
public int getSegmentIndex() { public int getSegmentIndex() {
return segmentIndex; return segmentIndex;
} }
@ -99,22 +99,22 @@ public class OmfIteratedData extends OmfRecord implements OmfData {
private int blockCount; private int blockCount;
private byte[] simpleBlock = null; private byte[] simpleBlock = null;
private DataBlock[] nestedBlock = null; private DataBlock[] nestedBlock = null;
public static DataBlock read(BinaryReader reader,boolean hasBigFields) throws IOException { public static DataBlock read(BinaryReader reader, boolean hasBigFields) throws IOException {
DataBlock subblock = new DataBlock(); DataBlock subblock = new DataBlock();
subblock.repeatCount = OmfRecord.readInt2Or4(reader, hasBigFields); subblock.repeatCount = OmfRecord.readInt2Or4(reader, hasBigFields);
subblock.blockCount = reader.readNextShort() & 0xffff; subblock.blockCount = reader.readNextShort() & 0xffff;
if (subblock.blockCount == 0) { if (subblock.blockCount == 0) {
int size = reader.readNextByte() & 0xff; int size = reader.readNextByte() & 0xff;
subblock.simpleBlock = new byte[ size ]; subblock.simpleBlock = new byte[size];
for(int i=0;i<size;++i) { for (int i = 0; i < size; ++i) {
subblock.simpleBlock[i] = reader.readNextByte(); subblock.simpleBlock[i] = reader.readNextByte();
} }
} }
else { else {
subblock.nestedBlock = new DataBlock[subblock.blockCount]; subblock.nestedBlock = new DataBlock[subblock.blockCount];
for(int i=0;i<subblock.blockCount;++i) { for (int i = 0; i < subblock.blockCount; ++i) {
subblock.nestedBlock[i] = read(reader,hasBigFields); // Recursive definition subblock.nestedBlock[i] = read(reader, hasBigFields); // Recursive definition
} }
} }
return subblock; return subblock;

View file

@ -15,12 +15,12 @@
*/ */
package ghidra.app.util.bin.format.omf; package ghidra.app.util.bin.format.omf;
import ghidra.app.util.bin.BinaryReader;
import ghidra.util.task.TaskMonitor;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import ghidra.app.util.bin.BinaryReader;
import ghidra.util.task.TaskMonitor;
public class OmfLibraryRecord extends OmfRecord { public class OmfLibraryRecord extends OmfRecord {
private int pageSize; // All archive members must start on a page boundary of this size private int pageSize; // All archive members must start on a page boundary of this size
private long dictionaryOffset; private long dictionaryOffset;
@ -35,7 +35,7 @@ public class OmfLibraryRecord extends OmfRecord {
public String translator; public String translator;
public String machineName; public String machineName;
} }
public OmfLibraryRecord(BinaryReader reader) throws IOException { public OmfLibraryRecord(BinaryReader reader) throws IOException {
readRecordHeader(reader); readRecordHeader(reader);
pageSize = recordLength + 3; pageSize = recordLength + 3;
@ -44,62 +44,75 @@ public class OmfLibraryRecord extends OmfRecord {
flags = reader.readNextByte(); flags = reader.readNextByte();
// No checksum byte (just padding) // No checksum byte (just padding)
} }
public int getPageSize() { public int getPageSize() {
return pageSize; return pageSize;
} }
public ArrayList<MemberHeader> getMemberHeaders() { public ArrayList<MemberHeader> getMemberHeaders() {
return members; return members;
} }
public static boolean checkMagicNumer(BinaryReader reader) throws IOException { public static boolean checkMagicNumer(BinaryReader reader) throws IOException {
byte type = reader.readNextByte(); byte type = reader.readNextByte();
if (type != (byte)0xF0) if (type != (byte) 0xF0) {
return false; return false;
}
int pageSize = (reader.readNextShort() & 0xffff) + 3; int pageSize = (reader.readNextShort() & 0xffff) + 3;
// Make sure page size is a power of 2, 2^4 - 2^15 // Make sure page size is a power of 2, 2^4 - 2^15
int count = 0; int count = 0;
int mask = pageSize; int mask = pageSize;
while((mask & 1)==0) { while ((mask & 1) == 0) {
count += 1; count += 1;
mask >>>= 1; mask >>>= 1;
} }
if (mask != 1) return false; // Test if this is a power of 2 if (mask != 1) {
if (count < 4) return false; return false; // Test if this is a power of 2
if (count > 15) return false; }
if (count < 4) {
return false;
}
if (count > 15) {
return false;
}
reader.align(pageSize); reader.align(pageSize);
type = reader.readNextByte(); type = reader.readNextByte();
if ((type & 0xfc) != 0x80) return false; if ((type & 0xfc) != 0x80) {
return false;
}
return true; return true;
} }
public static OmfLibraryRecord parse(BinaryReader reader,TaskMonitor monitor) throws IOException { public static OmfLibraryRecord parse(BinaryReader reader, TaskMonitor monitor)
throws IOException {
OmfLibraryRecord res = null; OmfLibraryRecord res = null;
byte type = reader.peekNextByte(); byte type = reader.peekNextByte();
if (type != (byte)0xF0) if (type != (byte) 0xF0) {
throw new IOException("Not an OMF Library record"); throw new IOException("Not an OMF Library record");
}
res = new OmfLibraryRecord(reader); res = new OmfLibraryRecord(reader);
res.members = new ArrayList<MemberHeader>(); res.members = new ArrayList<MemberHeader>();
reader.align(res.pageSize); // Skip padding to get to next page boundary reader.align(res.pageSize); // Skip padding to get to next page boundary
type = reader.peekNextByte(); type = reader.peekNextByte();
while(type != (byte)0xF1) { // Until we see the official "end of library" record while (type != (byte) 0xF1) { // Until we see the official "end of library" record
MemberHeader curheader = new MemberHeader(); MemberHeader curheader = new MemberHeader();
curheader.payloadOffset = reader.getPointerIndex(); curheader.payloadOffset = reader.getPointerIndex();
OmfFileHeader fileheader; OmfFileHeader fileheader;
try { try {
fileheader = OmfFileHeader.scan(reader, monitor,false); fileheader = OmfFileHeader.scan(reader, monitor, false);
} catch (OmfException e) { }
catch (OmfException e) {
throw new IOException("Could not parse individual object file within archive"); throw new IOException("Could not parse individual object file within archive");
} }
curheader.name = fileheader.getLibraryModuleName(); // (preferred) name of the object module curheader.name = fileheader.getLibraryModuleName(); // (preferred) name of the object module
if (curheader.name == null) if (curheader.name == null) {
curheader.name = fileheader.getName(); // As a back-up, this is usually the name of the original source curheader.name = fileheader.getName(); // As a back-up, this is usually the name of the original source
}
curheader.machineName = fileheader.getMachineName(); curheader.machineName = fileheader.getMachineName();
curheader.translator = fileheader.getTranslator(); curheader.translator = fileheader.getTranslator();
curheader.size = (int)(reader.getPointerIndex() - curheader.payloadOffset); curheader.size = (int) (reader.getPointerIndex() - curheader.payloadOffset);
res.members.add(curheader); res.members.add(curheader);
reader.align(res.pageSize); // Skip padding to get to next page boundary reader.align(res.pageSize); // Skip padding to get to next page boundary
type = reader.peekNextByte(); type = reader.peekNextByte();
} }

View file

@ -1,55 +0,0 @@
/* ###
* 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.ArrayList;
import ghidra.app.util.bin.BinaryReader;
public class OmfLineNumberRecord extends OmfRecord {
private int baseGroup;
private int baseSegment;
private LineSubrecord[] linenumber;
public OmfLineNumberRecord(BinaryReader reader) throws IOException {
readRecordHeader(reader);
boolean hasBigFields = hasBigFields();
baseGroup = OmfRecord.readIndex(reader);
baseSegment = OmfRecord.readIndex(reader);
long max = reader.getPointerIndex() + getRecordLength() - 1;
ArrayList<LineSubrecord> linelist = new ArrayList<LineSubrecord>();
while(reader.getPointerIndex() < max) {
LineSubrecord subrec = LineSubrecord.read(reader,hasBigFields);
linelist.add(subrec);
}
readCheckSumByte(reader);
linenumber = new LineSubrecord[linelist.size()];
linelist.toArray(linenumber);
}
public static class LineSubrecord {
private int lineNumber;
private int lineNumberOffset;
public static LineSubrecord read(BinaryReader reader,boolean hasBigFields) throws IOException {
LineSubrecord subrec = new LineSubrecord();
subrec.lineNumber = reader.readNextShort() & 0xffff;
subrec.lineNumberOffset = OmfRecord.readInt2Or4(reader, hasBigFields);
return subrec;
}
}
}

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,20 +22,21 @@ import ghidra.app.util.bin.BinaryReader;
public class OmfModuleEnd extends OmfRecord { public class OmfModuleEnd extends OmfRecord {
private byte moduleType; private byte moduleType;
private OmfFixupRecord.FixupTarget startAddress; private OmfFixupRecord.FixupTarget startAddress;
public OmfModuleEnd(BinaryReader reader) throws IOException { public OmfModuleEnd(BinaryReader reader) throws IOException {
readRecordHeader(reader); readRecordHeader(reader);
moduleType = reader.readNextByte(); moduleType = reader.readNextByte();
if (hasStartAddress()) if (hasStartAddress()) {
startAddress = OmfFixupRecord.FixupTarget.readFixupTarget(reader,hasBigFields()); startAddress = OmfFixupRecord.FixupTarget.readFixupTarget(reader, hasBigFields());
}
readCheckSumByte(reader); readCheckSumByte(reader);
} }
public boolean isMainProgramModule() { public boolean isMainProgramModule() {
return ((moduleType & 0x80)!=0); return ((moduleType & 0x80) != 0);
} }
public boolean hasStartAddress() { public boolean hasStartAddress() {
return ((moduleType & 0x40)!=0); return ((moduleType & 0x40) != 0);
} }
} }

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,18 +22,18 @@ import ghidra.app.util.bin.BinaryReader;
public class OmfNamesRecord extends OmfRecord { public class OmfNamesRecord extends OmfRecord {
private ArrayList<String> name; private ArrayList<String> name;
public OmfNamesRecord(BinaryReader reader) throws IOException { public OmfNamesRecord(BinaryReader reader) throws IOException {
readRecordHeader(reader); readRecordHeader(reader);
long max = reader.getPointerIndex() + getRecordLength() -1; long max = reader.getPointerIndex() + getRecordLength() - 1;
name = new ArrayList<String>(); name = new ArrayList<String>();
while(reader.getPointerIndex() < max) { while (reader.getPointerIndex() < max) {
String nm = OmfRecord.readString(reader); String nm = OmfRecord.readString(reader);
name.add(nm); name.add(nm);
} }
readCheckSumByte(reader); readCheckSumByte(reader);
} }
public void appendNames(ArrayList<String> namelist) { public void appendNames(ArrayList<String> namelist) {
namelist.addAll(name); namelist.addAll(name);
} }

View file

@ -0,0 +1,34 @@
/* ###
* 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 ghidra.app.util.bin.BinaryReader;
public class OmfObsoleteRecord extends OmfRecord {
/**
* Create a new {@link OmfObsoleteRecord}
*
* @param reader A {@link BinaryReader} positioned at the start of the record
* @throws IOException If an IO-related error occurred
*/
public OmfObsoleteRecord(BinaryReader reader) throws IOException {
readRecordHeader(reader);
reader.setPointerIndex(reader.getPointerIndex() + getRecordLength());
}
}

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,156 +16,236 @@
package ghidra.app.util.bin.format.omf; package ghidra.app.util.bin.format.omf;
import java.io.IOException; 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.BinaryReader;
public abstract class OmfRecord { public abstract class OmfRecord {
public final static byte THEADR = (byte)0x80; public final static byte RHEADR = (byte) 0x6E; // Obsolete
public final static byte LHEADR = (byte)0x82; public final static byte REGINT = (byte) 0x70; // Obsolete
public final static byte COMENT = (byte)0x88; public final static byte REDATA = (byte) 0x72; // Obsolete
public final static byte MODEND = (byte)0x8A; public final static byte RIDATA = (byte) 0x74; // Obsolete
public final static byte EXTDEF = (byte)0x8C; public final static byte OVLDEF = (byte) 0x76; // Obsolete
public final static byte PUBDEF = (byte)0x90; public final static byte ENDREC = (byte) 0x78; // Obsolete
public final static byte LINNUM = (byte)0x94; public final static byte BLKDEF = (byte) 0x7A; // Obsolete
public final static byte LNAMES = (byte)0x96; public final static byte BLKEND = (byte) 0x7C; // Obsolete
public final static byte SEGDEF = (byte)0x98; public final static byte DEBSYM = (byte) 0x7E; // Obsolete
public final static byte GRPDEF = (byte)0x9A; public final static byte THEADR = (byte) 0x80;
public final static byte FIXUPP = (byte)0x9C; public final static byte LHEADR = (byte) 0x82;
public final static byte LEDATA = (byte)0xA0; public final static byte PEDATA = (byte) 0x84; // Obsolete
public final static byte LIDATA = (byte)0xA2; public final static byte PIDATA = (byte) 0x86; // Obsolete
public final static byte COMDEF = (byte)0xB0; public final static byte COMENT = (byte) 0x88;
public final static byte LEXTDEF = (byte)0xB4; public final static byte MODEND = (byte) 0x8A;
public final static byte LPUBDEF = (byte)0xB6; public final static byte EXTDEF = (byte) 0x8C;
public final static byte LCOMDEF = (byte)0xB8; 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 byte recordType; protected byte recordType;
protected int recordLength; protected int recordLength;
protected long recordOffset;
protected byte checkSum; protected byte checkSum;
public byte getRecordType() { public byte getRecordType() {
return recordType; return recordType;
} }
public int getRecordLength() { public int getRecordLength() {
return recordLength; return recordLength;
} }
public long getRecordOffset() {
return recordOffset;
}
public void readRecordHeader(BinaryReader reader) throws IOException { public void readRecordHeader(BinaryReader reader) throws IOException {
recordOffset = reader.getPointerIndex();
recordType = reader.readNextByte(); recordType = reader.readNextByte();
recordLength = reader.readNextShort() & 0xffff; recordLength = reader.readNextShort() & 0xffff;
} }
public void readCheckSumByte(BinaryReader reader) throws IOException { public void readCheckSumByte(BinaryReader reader) throws IOException {
checkSum = reader.readNextByte(); checkSum = reader.readNextByte();
} }
public byte calcCheckSum(BinaryReader reader) throws IOException { public byte calcCheckSum(BinaryReader reader) throws IOException {
byte res = reader.readNextByte(); byte res = reader.readNextByte();
res += reader.readNextByte(); res += reader.readNextByte();
res += reader.readNextByte(); // Sum the record header bytes 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(); res += reader.readNextByte();
return res; return res;
} }
public boolean validCheckSum(BinaryReader reader) throws IOException { public boolean validCheckSum(BinaryReader reader) throws IOException {
if (checkSum == 0) return true; // Sum compilers just set this to zero if (checkSum == 0)
return true; // Sum compilers just set this to zero
return (calcCheckSum(reader) == 0); return (calcCheckSum(reader) == 0);
} }
public boolean hasBigFields() { public boolean hasBigFields() {
return ((recordType & 1)!=0); return ((recordType & 1) != 0);
} }
public static int readInt1Or2(BinaryReader reader,boolean isBig) throws IOException { public static int readInt1Or2(BinaryReader reader, boolean isBig) throws IOException {
if (isBig) if (isBig)
return (reader.readNextShort() & 0xffff); return (reader.readNextShort() & 0xffff);
return (reader.readNextByte() & 0xff); return (reader.readNextByte() & 0xff);
} }
public static int readInt2Or4(BinaryReader reader,boolean isBig) throws IOException { public static int readInt2Or4(BinaryReader reader, boolean isBig) throws IOException {
if (isBig) if (isBig)
return reader.readNextInt(); return reader.readNextInt();
return (reader.readNextShort() & 0xffff); return (reader.readNextShort() & 0xffff);
} }
public static int readIndex(BinaryReader reader) throws IOException { public static int readIndex(BinaryReader reader) throws IOException {
int indexWord; int indexWord;
byte firstByte = reader.readNextByte(); byte firstByte = reader.readNextByte();
if ((firstByte & 0x80)!=0) if ((firstByte & 0x80) != 0) {
indexWord = (firstByte & 0x7f) * 0x100 + (reader.readNextByte() & 0xff); indexWord = (firstByte & 0x7f) * 0x100 + (reader.readNextByte() & 0xff);
else }
else {
indexWord = firstByte; indexWord = firstByte;
}
return indexWord; return indexWord;
} }
public static OmfRecord readRecord(BinaryReader reader) throws IOException, OmfException { public static OmfRecord readRecord(BinaryReader reader) throws IOException, OmfException {
OmfRecord res = null;
byte type = reader.peekNextByte(); byte type = reader.peekNextByte();
type &= 0xfe; // Mask off the least significant bit type &= 0xfe; // Mask off the least significant bit (16/32 bit flag)
switch(type) { return switch (type) {
case THEADR: case THEADR:
case LHEADR: case LHEADR:
res = new OmfFileHeader(reader); yield new OmfFileHeader(reader);
break; case COMENT:
case COMENT: yield new OmfCommentRecord(reader);
res = new OmfCommentRecord(reader); case MODEND:
break; yield new OmfModuleEnd(reader);
case MODEND: case EXTDEF:
res = new OmfModuleEnd(reader); yield new OmfExternalSymbol(reader, false);
break; case PUBDEF:
case EXTDEF: yield new OmfSymbolRecord(reader, false);
res = new OmfExternalSymbol(reader,false); case LNAMES:
break; yield new OmfNamesRecord(reader);
case PUBDEF: case SEGDEF:
res = new OmfSymbolRecord(reader,false); yield new OmfSegmentHeader(reader);
break; case GRPDEF:
case LINNUM: yield new OmfGroupRecord(reader);
res = new OmfLineNumberRecord(reader); case FIXUPP:
break; yield new OmfFixupRecord(reader);
case LNAMES: case LEDATA:
res = new OmfNamesRecord(reader); yield new OmfEnumeratedData(reader);
break; case LIDATA:
case SEGDEF: yield new OmfIteratedData(reader);
res = new OmfSegmentHeader(reader); case COMDEF:
break; yield new OmfComdefRecord(reader, false);
case GRPDEF: case LEXTDEF:
res = new OmfGroupRecord(reader); yield new OmfExternalSymbol(reader, true);
break; case LPUBDEF:
case FIXUPP: yield new OmfSymbolRecord(reader, true);
res = new OmfFixupRecord(reader); case LCOMDEF:
break; yield new OmfComdefRecord(reader, true);
case LEDATA: case RHEADR:
res = new OmfEnumeratedData(reader); case REGINT:
break; case REDATA:
case LIDATA: case RIDATA:
res = new OmfIteratedData(reader); case OVLDEF:
break; case ENDREC:
case COMDEF: case BLKDEF:
res = new OmfComdefRecord(reader,false); case BLKEND:
break; case DEBSYM:
case LEXTDEF: case LINNUM:
res = new OmfExternalSymbol(reader,true); case PEDATA:
break; case PIDATA:
case LPUBDEF: case LIBHED:
res = new OmfSymbolRecord(reader,true); case LIBNAM:
break; case LIBLOC:
case LCOMDEF: case LIBDIC:
res = new OmfComdefRecord(reader,true); yield new OmfObsoleteRecord(reader);
break; case LOCSYM:
default: case TYPDEF:
throw new OmfException("Unrecognized record type"); case CEXTDEF:
} case COMDAT:
return res; 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 * Read the OMF string format: 1-byte length, followed by that many ascii characters
* @param reader *
* @return * @param reader A {@link BinaryReader} positioned at the start of the string
* @throws IOException * @return the read OMF string
* @throws IOException if an IO-related error occurred
*/ */
public static String readString(BinaryReader reader) throws IOException { public static String readString(BinaryReader reader) throws IOException {
int count = reader.readNextByte() & 0xff; int count = reader.readNextByte() & 0xff;
return reader.readNextAsciiString(count); return 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 String toString() {
return String.format("name: %s, type: 0x%x, offset: 0x%x, length: 0x%x",
getRecordName(recordType), recordType, recordOffset, recordLength);
}
} }

View file

@ -45,9 +45,9 @@ public class OmfSegmentHeader extends OmfRecord {
private long vma = -1; // assigned (by linker) starting address of segment -1 means unset private long vma = -1; // assigned (by linker) starting address of segment -1 means unset
private ArrayList<OmfData> dataBlocks = new ArrayList<OmfData>(); private ArrayList<OmfData> dataBlocks = new ArrayList<OmfData>();
OmfSegmentHeader(int num,int datatype) { OmfSegmentHeader(int num, int datatype) {
// generate a special Borland header // generate a special Borland header
segAttr = (byte)0xa9; segAttr = (byte) 0xa9;
segmentLength = 0; segmentLength = 0;
segmentNameIndex = 0; segmentNameIndex = 0;
classNameIndex = 0; classNameIndex = 0;
@ -62,7 +62,7 @@ public class OmfSegmentHeader extends OmfRecord {
else { else {
segmentName = "EXTRA_"; segmentName = "EXTRA_";
} }
segmentName = segmentName+Integer.toString(num); segmentName = segmentName + Integer.toString(num);
if (datatype == 1) { if (datatype == 1) {
// Treat as a text segment // Treat as a text segment
className = "TEXT"; className = "TEXT";
@ -79,7 +79,7 @@ public class OmfSegmentHeader extends OmfRecord {
isExecutable = false; isExecutable = false;
} }
} }
public OmfSegmentHeader(BinaryReader reader) throws IOException { public OmfSegmentHeader(BinaryReader reader) throws IOException {
readRecordHeader(reader); readRecordHeader(reader);
boolean hasBigFields = hasBigFields(); boolean hasBigFields = hasBigFields();
@ -88,15 +88,15 @@ public class OmfSegmentHeader extends OmfRecord {
if (A == 0) { if (A == 0) {
frameNumber = reader.readNextShort() & 0xffff; frameNumber = reader.readNextShort() & 0xffff;
offset = reader.readNextByte() & 0xff; offset = reader.readNextByte() & 0xff;
vma = (long)frameNumber + offset; vma = (long) frameNumber + offset;
} }
segmentLength = OmfRecord.readInt2Or4(reader, hasBigFields) & 0xffffffffL; segmentLength = OmfRecord.readInt2Or4(reader, hasBigFields) & 0xffffffffL;
segmentNameIndex = OmfRecord.readIndex(reader); segmentNameIndex = OmfRecord.readIndex(reader);
classNameIndex = OmfRecord.readIndex(reader); classNameIndex = OmfRecord.readIndex(reader);
overlayNameIndex = OmfRecord.readIndex(reader); overlayNameIndex = OmfRecord.readIndex(reader);
readCheckSumByte(reader); readCheckSumByte(reader);
int B = (segAttr>>1) & 1; int B = (segAttr >> 1) & 1;
if (B==1) { // Ignore the segmentLength field if (B == 1) { // Ignore the segmentLength field
if (getRecordType() == OmfRecord.SEGDEF) { if (getRecordType() == OmfRecord.SEGDEF) {
segmentLength = 0x10000L; // Exactly 64K segment segmentLength = 0x10000L; // Exactly 64K segment
} }
@ -105,28 +105,28 @@ public class OmfSegmentHeader extends OmfRecord {
} }
} }
} }
/** /**
* @return true if this is a code segment * @return true if this is a code segment
*/ */
public boolean isCode() { public boolean isCode() {
return isCode; return isCode;
} }
/** /**
* @return true if this segment is readable * @return true if this segment is readable
*/ */
public boolean isReadable() { public boolean isReadable() {
return isReadable; return isReadable;
} }
/** /**
* @return true if this segment is writable * @return true if this segment is writable
*/ */
public boolean isWritable() { public boolean isWritable() {
return isWritable; return isWritable;
} }
/** /**
* @return true if this segment is executable * @return true if this segment is executable
*/ */
@ -140,7 +140,7 @@ public class OmfSegmentHeader extends OmfRecord {
public int getFrameDatum() { public int getFrameDatum() {
return 0; // TODO: Need to fill in a real segment selector return 0; // TODO: Need to fill in a real segment selector
} }
/** /**
* @param language is the Program language for this binary * @param language is the Program language for this binary
* @return the starting Address for this segment * @return the starting Address for this segment
@ -150,26 +150,27 @@ public class OmfSegmentHeader extends OmfRecord {
if (isCode) { if (isCode) {
addrSpace = language.getDefaultSpace(); addrSpace = language.getDefaultSpace();
} else { }
else {
addrSpace = language.getDefaultDataSpace(); addrSpace = language.getDefaultDataSpace();
} }
return addrSpace.getAddress(vma); return addrSpace.getAddress(vma);
} }
/** /**
* @return the name of this segment * @return the name of this segment
*/ */
public String getName() { public String getName() {
return segmentName; return segmentName;
} }
/** /**
* @return the class name of this segment * @return the class name of this segment
*/ */
public String getClassName() { public String getClassName() {
return className; return className;
} }
/** /**
* @return the name of the overlay, or the empty string * @return the name of the overlay, or the empty string
*/ */
@ -183,21 +184,21 @@ public class OmfSegmentHeader extends OmfRecord {
public long getStartAddress() { public long getStartAddress() {
return vma; return vma;
} }
/** /**
* @return the length of the segment in bytes * @return the length of the segment in bytes
*/ */
public long getSegmentLength() { public long getSegmentLength() {
return segmentLength; return segmentLength;
} }
/** /**
* @return the alignment required for this segment * @return the alignment required for this segment
*/ */
public int getAlignment() { public int getAlignment() {
return (segAttr >> 5) & 0x7; return (segAttr >> 5) & 0x7;
} }
/** /**
* @return special combining rules for this segment * @return special combining rules for this segment
*/ */
@ -223,7 +224,7 @@ public class OmfSegmentHeader extends OmfRecord {
protected void sortData() { protected void sortData() {
Collections.sort(dataBlocks); Collections.sort(dataBlocks);
} }
/** /**
* Get an InputStream that reads in the raw data for this segment * Get an InputStream that reads in the raw data for this segment
* @param reader is the image file reader * @param reader is the image file reader
@ -234,7 +235,7 @@ public class OmfSegmentHeader extends OmfRecord {
public InputStream getRawDataStream(BinaryReader reader, MessageLog log) throws IOException { public InputStream getRawDataStream(BinaryReader reader, MessageLog log) throws IOException {
return new SectionStream(reader, log); return new SectionStream(reader, log);
} }
/** /**
* Given the first possible address where this segment can reside, relocate the * Given the first possible address where this segment can reside, relocate the
* segment based on this address and alignment considerations. * segment based on this address and alignment considerations.
@ -244,35 +245,35 @@ public class OmfSegmentHeader extends OmfRecord {
* @throws OmfException for bad alignment information * @throws OmfException for bad alignment information
*/ */
protected long relocateSegment(long firstValidAddress, int alignOverride) throws OmfException { protected long relocateSegment(long firstValidAddress, int alignOverride) throws OmfException {
int align = getAlignment(); int align = getAlignment();
if (alignOverride >= 0) { if (alignOverride >= 0) {
align = alignOverride; align = alignOverride;
} }
switch(align) { switch (align) {
case 0: // Absolute segment, not relocatable case 0: // Absolute segment, not relocatable
throw new OmfException("Trying to relocate an absolute segment"); throw new OmfException("Trying to relocate an absolute segment");
case 1: // Byte aligned case 1: // Byte aligned
break; // Keep the first valid address break; // Keep the first valid address
case 2: // 2-byte aligned case 2: // 2-byte aligned
firstValidAddress = (firstValidAddress+1 ) & 0xfffffffffffffffeL; firstValidAddress = (firstValidAddress + 1) & 0xfffffffffffffffeL;
break; break;
case 3: // 16-byte aligned case 3: // 16-byte aligned
firstValidAddress = (firstValidAddress+15) & 0xfffffffffffffff0L; firstValidAddress = (firstValidAddress + 15) & 0xfffffffffffffff0L;
break; break;
case 4: // "page" aligned, assume 4096 case 4: // "page" aligned, assume 4096
firstValidAddress = (firstValidAddress+4095) & 0xfffffffffffff000L; firstValidAddress = (firstValidAddress + 4095) & 0xfffffffffffff000L;
break; break;
case 5: // 4-byte aligned case 5: // 4-byte aligned
firstValidAddress = (firstValidAddress+3) & 0xfffffffffffffffcL; firstValidAddress = (firstValidAddress + 3) & 0xfffffffffffffffcL;
break; break;
default: default:
throw new OmfException("Unsupported alignment type"); throw new OmfException("Unsupported alignment type");
} }
vma = firstValidAddress; vma = firstValidAddress;
firstValidAddress = vma + segmentLength; firstValidAddress = vma + segmentLength;
return firstValidAddress; return firstValidAddress;
} }
/** /**
* Resolve special names from the name list such as: segment, class, overlay, names. * Resolve special names from the name list such as: segment, class, overlay, names.
* This routine also determines the read/write/execute permissions for the segment * This routine also determines the read/write/execute permissions for the segment
@ -308,7 +309,7 @@ public class OmfSegmentHeader extends OmfRecord {
} }
overlayName = nameList.get(overlayNameIndex - 1); overlayName = nameList.get(overlayNameIndex - 1);
} }
// Once we know the class name, we can make some educated guesses about read/write/exec permissions // Once we know the class name, we can make some educated guesses about read/write/exec permissions
isReadable = true; isReadable = true;
if (className.equals("CODE") || className.equals("code")) { if (className.equals("CODE") || className.equals("code")) {
@ -322,7 +323,7 @@ public class OmfSegmentHeader extends OmfRecord {
isExecutable = false; isExecutable = false;
} }
} }
/** /**
* Add an explicit data-block to this segment. * Add an explicit data-block to this segment.
* @param rec is the data-block * @param rec is the data-block
@ -330,7 +331,7 @@ public class OmfSegmentHeader extends OmfRecord {
protected void addEnumeratedData(OmfEnumeratedData rec) { protected void addEnumeratedData(OmfEnumeratedData rec) {
dataBlocks.add(rec); dataBlocks.add(rec);
} }
/** /**
* Add an explicit data-block to this segment that might extend * Add an explicit data-block to this segment that might extend
* the length of this segment. Borland compilers in particular produce * the length of this segment. Borland compilers in particular produce
@ -344,7 +345,7 @@ public class OmfSegmentHeader extends OmfRecord {
} }
dataBlocks.add(rec); dataBlocks.add(rec);
} }
/** /**
* Add a compressed-form data-block to this segment * Add a compressed-form data-block to this segment
* @param rec is the data-block * @param rec is the data-block
@ -352,7 +353,7 @@ public class OmfSegmentHeader extends OmfRecord {
protected void addIteratedData(OmfIteratedData rec) { protected void addIteratedData(OmfIteratedData rec) {
dataBlocks.add(rec); dataBlocks.add(rec);
} }
/** /**
* An InputStream that produces the bytes for the dataBlocks in this segment. * An InputStream that produces the bytes for the dataBlocks in this segment.
* It runs through the ordered {@link OmfData} in turn. It pads with zeroes, * It runs through the ordered {@link OmfData} in turn. It pads with zeroes,
@ -365,7 +366,7 @@ public class OmfSegmentHeader extends OmfRecord {
private byte[] buffer; // Current buffer private byte[] buffer; // Current buffer
private int bufferpointer; // current index into buffer private int bufferpointer; // current index into buffer
private int dataUpNext; // Index of next data section OmfIteratedData/OmfEnumeratedData to be buffered private int dataUpNext; // Index of next data section OmfIteratedData/OmfEnumeratedData to be buffered
public SectionStream(BinaryReader reader, MessageLog log) throws IOException { public SectionStream(BinaryReader reader, MessageLog log) throws IOException {
super(); super();
this.reader = reader; this.reader = reader;
@ -376,7 +377,7 @@ public class OmfSegmentHeader extends OmfRecord {
establishNextBuffer(); establishNextBuffer();
} }
} }
/** /**
* Fill the next buffer of bytes being provided by this stream. * Fill the next buffer of bytes being provided by this stream.
* @throws IOException for problems with the file image reader * @throws IOException for problems with the file image reader
@ -388,10 +389,11 @@ public class OmfSegmentHeader extends OmfRecord {
// We have some fill to produce before the next section // We have some fill to produce before the next section
long size = data.getDataOffset() - pointer; long size = data.getDataOffset() - pointer;
if (size > OmfLoader.MAX_UNINITIALIZED_FILL) { if (size > OmfLoader.MAX_UNINITIALIZED_FILL) {
throw new IOException("Unfilled hole in OMF data blocks for segment: "+segmentName); throw new IOException(
"Unfilled hole in OMF data blocks for segment: " + segmentName);
} }
buffer = new byte[(int)size]; buffer = new byte[(int) size];
for(int i=0;i<size;++i) { for (int i = 0; i < size; ++i) {
buffer[i] = 0; buffer[i] = 0;
} }
bufferpointer = 0; bufferpointer = 0;
@ -416,15 +418,15 @@ public class OmfSegmentHeader extends OmfRecord {
// We may have filler after the last block // We may have filler after the last block
long size = segmentLength - pointer; long size = segmentLength - pointer;
if (size > OmfLoader.MAX_UNINITIALIZED_FILL) { if (size > OmfLoader.MAX_UNINITIALIZED_FILL) {
throw new IOException("Large hole at the end of OMF segment: "+segmentName); throw new IOException("Large hole at the end of OMF segment: " + segmentName);
} }
buffer = new byte[(int)size]; buffer = new byte[(int) size];
for(int i=0;i<size;++i) { for (int i = 0; i < size; ++i) {
buffer[i] = 0; buffer[i] = 0;
} }
bufferpointer = 0; bufferpointer = 0;
} }
@Override @Override
public int read() throws IOException { public int read() throws IOException {
if (pointer < segmentLength) { if (pointer < segmentLength) {
@ -443,6 +445,6 @@ public class OmfSegmentHeader extends OmfRecord {
} }
return -1; return -1;
} }
} }
} }

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,46 +22,46 @@ public class OmfSymbol {
private int typeIndex; private int typeIndex;
private int dataType; // 0=unused private int dataType; // 0=unused
private int byteLength; // 0=unused private int byteLength; // 0=unused
private int segmentRef=0; // Symbol is really reference to extra segment private int segmentRef = 0; // Symbol is really reference to extra segment
private long offset; private long offset;
private Address address; private Address address;
public OmfSymbol(String name,int type,long off,int dT,int bL) { public OmfSymbol(String name, int type, long off, int dT, int bL) {
symbolName = name; symbolName = name;
typeIndex = type; typeIndex = type;
offset = off; offset = off;
dataType = dT; dataType = dT;
byteLength = bL; byteLength = bL;
} }
public String getName() { public String getName() {
return symbolName; return symbolName;
} }
public int getDataType() { public int getDataType() {
return dataType; return dataType;
} }
public long getOffset() { public long getOffset() {
return offset; return offset;
} }
public int getSegmentRef() { public int getSegmentRef() {
return segmentRef; return segmentRef;
} }
public void setSegmentRef(int val) { public void setSegmentRef(int val) {
segmentRef = val; segmentRef = val;
} }
public void setAddress(Address addr) { public void setAddress(Address addr) {
address = addr; address = addr;
} }
public Address getAddress() { public Address getAddress() {
return address; return address;
} }
public int getFrameDatum() { public int getFrameDatum() {
return 0; // This is currently unused return 0; // This is currently unused
} }

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -27,23 +26,24 @@ public class OmfSymbolRecord extends OmfRecord {
private int baseFrame; private int baseFrame;
private boolean isStatic; private boolean isStatic;
private OmfSymbol[] symbol; private OmfSymbol[] symbol;
public OmfSymbolRecord(BinaryReader reader,boolean isStatic) throws IOException { public OmfSymbolRecord(BinaryReader reader, boolean isStatic) throws IOException {
this.isStatic = isStatic; this.isStatic = isStatic;
readRecordHeader(reader); readRecordHeader(reader);
long max = reader.getPointerIndex() + getRecordLength() - 1; long max = reader.getPointerIndex() + getRecordLength() - 1;
boolean hasBigFields = hasBigFields(); boolean hasBigFields = hasBigFields();
baseGroupIndex = OmfRecord.readIndex(reader); baseGroupIndex = OmfRecord.readIndex(reader);
baseSegmentIndex = OmfRecord.readIndex(reader); baseSegmentIndex = OmfRecord.readIndex(reader);
if (baseSegmentIndex == 0) if (baseSegmentIndex == 0) {
baseFrame = reader.readNextShort() & 0xffff; baseFrame = reader.readNextShort() & 0xffff;
}
ArrayList<OmfSymbol> symbollist = new ArrayList<OmfSymbol>(); ArrayList<OmfSymbol> symbollist = new ArrayList<OmfSymbol>();
while(reader.getPointerIndex() < max) { while (reader.getPointerIndex() < max) {
String name = OmfRecord.readString(reader); String name = OmfRecord.readString(reader);
long offset = OmfRecord.readInt2Or4(reader, hasBigFields) & 0xffffffffL; long offset = OmfRecord.readInt2Or4(reader, hasBigFields) & 0xffffffffL;
int type = OmfRecord.readIndex(reader); int type = OmfRecord.readIndex(reader);
OmfSymbol subrec = new OmfSymbol(name,type,offset,0,0); OmfSymbol subrec = new OmfSymbol(name, type, offset, 0, 0);
symbollist.add(subrec); symbollist.add(subrec);
} }
readCheckSumByte(reader); readCheckSumByte(reader);
@ -54,19 +54,19 @@ public class OmfSymbolRecord extends OmfRecord {
public boolean isStatic() { public boolean isStatic() {
return isStatic; return isStatic;
} }
public int getGroupIndex() { public int getGroupIndex() {
return baseGroupIndex; return baseGroupIndex;
} }
public int getSegmentIndex() { public int getSegmentIndex() {
return baseSegmentIndex; return baseSegmentIndex;
} }
public int numSymbols() { public int numSymbols() {
return symbol.length; return symbol.length;
} }
public OmfSymbol getSymbol(int i) { public OmfSymbol getSymbol(int i) {
return symbol[i]; return symbol[i];
} }

View file

@ -0,0 +1,34 @@
/* ###
* 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 ghidra.app.util.bin.BinaryReader;
public class OmfUnknownRecord extends OmfRecord {
/**
* Create a new {@link OmfUnknownRecord}
*
* @param reader A {@link BinaryReader} positioned at the start of the record
* @throws IOException If an IO-related error occurred
*/
public OmfUnknownRecord(BinaryReader reader) throws IOException {
readRecordHeader(reader);
reader.setPointerIndex(reader.getPointerIndex() + getRecordLength());
}
}

View file

@ -0,0 +1,34 @@
/* ###
* 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 ghidra.app.util.bin.BinaryReader;
public class OmfUnsupportedRecord extends OmfRecord {
/**
* Create a new {@link OmfUnsupportedRecord}
*
* @param reader A {@link BinaryReader} positioned at the start of the record
* @throws IOException If an IO-related error occurred
*/
public OmfUnsupportedRecord(BinaryReader reader) throws IOException {
readRecordHeader(reader);
reader.setPointerIndex(reader.getPointerIndex() + getRecordLength());
}
}

View file

@ -38,7 +38,6 @@ import ghidra.util.DataConverter;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.exception.InvalidInputException; import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
import ghidra.util.task.TaskMonitorAdapter;
public class OmfLoader extends AbstractProgramWrapperLoader { public class OmfLoader extends AbstractProgramWrapperLoader {
public final static String OMF_NAME = "Relocatable Object Module Format (OMF)"; public final static String OMF_NAME = "Relocatable Object Module Format (OMF)";
@ -115,7 +114,7 @@ public class OmfLoader extends AbstractProgramWrapperLoader {
OmfFileHeader header = null; OmfFileHeader header = null;
BinaryReader reader = OmfFileHeader.createReader(provider); BinaryReader reader = OmfFileHeader.createReader(provider);
try { try {
header = OmfFileHeader.parse(reader, monitor); header = OmfFileHeader.parse(reader, monitor, log);
header.resolveNames(); header.resolveNames();
header.sortSegmentDataBlocks(); header.sortSegmentDataBlocks();
OmfFileHeader.doLinking(IMAGE_BASE, header.getSegments(), header.getGroups()); OmfFileHeader.doLinking(IMAGE_BASE, header.getSegments(), header.getGroups());
@ -284,7 +283,6 @@ public class OmfLoader extends AbstractProgramWrapperLoader {
* @param reader is a reader for the underlying file * @param reader is a reader for the underlying file
* @param header is the OMF file header * @param header is the OMF file header
* @param program is the Program * @param program is the Program
* @param mbu is the block creation utility
* @param monitor is checked for cancellation * @param monitor is checked for cancellation
* @param log receives error messages * @param log receives error messages
* @throws AddressOverflowException if the underlying data stream causes an address to wrap * @throws AddressOverflowException if the underlying data stream causes an address to wrap