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 OmfComdefRecord(BinaryReader reader,boolean isStatic) throws IOException, OmfException {
public OmfComdefRecord(BinaryReader reader, boolean isStatic) throws IOException, OmfException {
super(isStatic);
readRecordHeader(reader);
long max = reader.getPointerIndex() + getRecordLength() - 1;
ArrayList<OmfSymbol> symbollist = new ArrayList<OmfSymbol>();
while(reader.getPointerIndex() < max) {
while (reader.getPointerIndex() < max) {
String name = OmfRecord.readString(reader);
int typeIndex = OmfRecord.readIndex(reader);
byte dataType = reader.readNextByte();
int byteLength=0;
int byteLength = 0;
if (dataType == 0x61) { // FAR data, reads numElements and elSize
int numElements = 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
byteLength = readCommunalLength(reader);
}
OmfSymbol sym = new OmfSymbol(name,typeIndex,0,dataType,byteLength);
OmfSymbol sym = new OmfSymbol(name, typeIndex, 0, dataType, byteLength);
symbollist.add(sym);
}
readCheckSumByte(reader);
symbol = new OmfSymbol[symbollist.size()];
symbollist.toArray(symbol);
}
private static int readCommunalLength(BinaryReader reader) throws OmfException, IOException {
int val = reader.readNextByte() & 0xff;
if (val <= 128)
if (val <= 128) {
return val;
}
if (val == 0x81) {
val = reader.readNextShort() & 0xffff;
}
@ -65,9 +66,10 @@ public class OmfComdefRecord extends OmfExternalSymbol {
else if (val == 0x88) {
val = reader.readNextInt();
}
else
else {
throw new OmfException("Illegal communal length encoding");
}
return val;
}
}

View file

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

View file

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

View file

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

View file

@ -15,19 +15,19 @@
*/
package ghidra.app.util.bin.format.omf;
import java.util.ArrayList;
import java.io.IOException;
import java.util.ArrayList;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.importer.MessageLog;
import ghidra.util.task.TaskMonitor;
public class OmfFileHeader extends OmfRecord {
private String objectName; // Name of the object module
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 libModuleName = null; // Name of the module (within a library)
private String translator = null; // Usually the compiler/linker used to produce this object
private boolean isLittleEndian;
private ArrayList<String> nameList = new ArrayList<String>(); // Indexable List of segment, group, ... names
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<OmfFixupRecord> fixup = new ArrayList<OmfFixupRecord>();
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 {
readRecordHeader(reader);
@ -44,7 +44,7 @@ public class OmfFileHeader extends OmfRecord {
readCheckSumByte(reader);
isLittleEndian = reader.isLittleEndian();
}
/**
* This is usually the original source filename
* @return the name
@ -52,7 +52,7 @@ public class OmfFileHeader extends OmfRecord {
public String getName() {
return objectName;
}
/**
* The name of the object module (within a library)
* @return the name
@ -60,14 +60,14 @@ public class OmfFileHeader extends OmfRecord {
public String getLibraryModuleName() {
return libModuleName;
}
/**
* @return the string identifying the architecture this object was compiled for
*/
public String getMachineName() {
return "i386"; // This is the only possibility
}
/**
* If the OMF file contains a "translator" record, this is usually a string
* indicating the compiler which produced the file.
@ -76,14 +76,14 @@ public class OmfFileHeader extends OmfRecord {
public String getTranslator() {
return translator;
}
/**
* @return true if the file describes the load image for a little endian architecture
*/
public boolean isLittleEndian() {
return isLittleEndian;
}
/**
* @return the list of segments in this file
*/
@ -97,7 +97,7 @@ public class OmfFileHeader extends OmfRecord {
public ArrayList<OmfSegmentHeader> getExtraSegments() {
return extraSeg;
}
/**
* @return the list of group records for this file
*/
@ -111,31 +111,31 @@ public class OmfFileHeader extends OmfRecord {
public ArrayList<OmfExternalSymbol> getExternalSymbols() {
return externsymbols;
}
/**
* @return the list of symbols exported by this file
*/
public ArrayList<OmfSymbolRecord> getPublicSymbols() {
return symbols;
}
/**
* @return the list of relocation records for this file
*/
public ArrayList<OmfFixupRecord> getFixups() {
return fixup;
}
/**
* Sort the explicit data-blocks for each segment into address order.
*/
public void sortSegmentDataBlocks() {
if (extraSeg != null) {
for(int i=0;i<extraSeg.size();++i) {
for (int i = 0; i < extraSeg.size(); ++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();
}
}
@ -149,16 +149,16 @@ public class OmfFileHeader extends OmfRecord {
int index = datablock.getSegmentIndex();
int subindex = -1;
OmfSegmentHeader segment;
if ((index & 0x4000)!=0) {
if ((index & 0x4000) != 0) {
subindex = index & 0x3fff;
index = 1;
segment = createOrFindBorlandSegment(subindex, 1);
}
else {
if ((index <=0)||(index>segments.size())) {
if ((index <= 0) || (index > segments.size())) {
throw new OmfException("Bad segment index");
}
segment = segments.get(index-1);
segment = segments.get(index - 1);
}
if (subindex != -1) {
segment.appendEnumeratedData(datablock);
@ -167,7 +167,7 @@ public class OmfFileHeader extends OmfRecord {
segment.addEnumeratedData(datablock);
}
}
/**
* Given an index, retrieve the specific segment it refers to. This
* 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 {
int subindex = -1;
OmfSegmentHeader res;
if ((index & 0x4000)!=0) {
if ((index & 0x4000) != 0) {
subindex = index & 0x3fff;
if ((subindex<=0)||(subindex>extraSeg.size())) {
if ((subindex <= 0) || (subindex > extraSeg.size())) {
throw new OmfException("Bad extra segment index");
}
res = extraSeg.get(subindex - 1);
return res;
}
if ((index <=0)||(index>segments.size())) {
if ((index <= 0) || (index > segments.size())) {
throw new OmfException("Bad segment index");
}
res = segments.get(index-1);
res = segments.get(index - 1);
return res;
}
/**
* Resolve special names associated with each segment: segment, class, overlay names
* and group: group name
@ -201,15 +201,15 @@ public class OmfFileHeader extends OmfRecord {
* @throws OmfException if any name indices are malformed
*/
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);
}
// 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);
}
}
/**
* Given an index, either find an existing Borland segment, or create a new one.
* 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
* @return the corresponding OmfSegmentHeader
*/
private OmfSegmentHeader createOrFindBorlandSegment(int index,int datatype) {
private OmfSegmentHeader createOrFindBorlandSegment(int index, int datatype) {
if (extraSeg == null) {
extraSeg = new ArrayList<OmfSegmentHeader>();
}
while(extraSeg.size() < index) {
while (extraSeg.size() < index) {
extraSeg.add(null);
}
OmfSegmentHeader segment = extraSeg.get(index-1);
OmfSegmentHeader segment = extraSeg.get(index - 1);
if (segment == null) {
segment = new OmfSegmentHeader(index,datatype);
extraSeg.set(index-1,segment);
segment = new OmfSegmentHeader(index, datatype);
extraSeg.set(index - 1, segment);
}
return segment;
}
private void evaluateComdef(OmfComdefRecord comdef) {
OmfSymbol[] coms = comdef.getSymbols();
for (OmfSymbol sym : coms) {
int dt = sym.getDataType();
if (dt >0 && dt < 0x60) { // A special borland segment symbol
int count = (extraSeg==null) ? 1 : extraSeg.size()+1;
createOrFindBorlandSegment(count,dt);
if (dt > 0 && dt < 0x60) { // A special borland segment symbol
int count = (extraSeg == null) ? 1 : extraSeg.size() + 1;
createOrFindBorlandSegment(count, dt);
sym.setSegmentRef(count);
}
}
}
@ -256,128 +256,127 @@ public class OmfFileHeader extends OmfRecord {
* @throws IOException for problems reading program data
* @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);
if ((record.getRecordType() & (byte)0xfc)!=OmfRecord.THEADR) {
if (!(record instanceof OmfFileHeader)) {
throw new OmfException("Object file does not start with proper header");
}
OmfFileHeader header = (OmfFileHeader)record;
byte type = record.getRecordType();
type &= 0xfe;
while(type != MODEND) {
if (monitor.isCancelled()) {
break; // Return what we have
}
OmfFileHeader header = (OmfFileHeader) record;
while (true) {
record = OmfRecord.readRecord(reader);
type = record.getRecordType();
type &= 0xfe; // Mask off the least significant bit
if (initialCommentsOnly && (type != COMENT)) {
if (monitor.isCancelled()) {
break;
}
switch(type) {
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) {
header.translator = ((OmfCommentRecord)record).getValue();
header.translator = comment.getValue();
}
else if (commentClass == OmfCommentRecord.COMMENT_CLASS_LIBMOD) {
header.libModuleName = ((OmfCommentRecord)record).getValue();
header.libModuleName = comment.getValue();
}
}
else if (initialCommentsOnly) {
break;
default:
break; // Skip most records
}
}
return header;
}
/**
* Parse the entire object file
*
* @param reader is the byte stream
* @param monitor is checked for cancel button
* @param log the log
* @return the header record as root of object
* @throws IOException for problems reading data
* @throws OmfException for malformed records
*/
public static OmfFileHeader parse(BinaryReader reader,TaskMonitor monitor) throws IOException, OmfException {
public static OmfFileHeader parse(BinaryReader reader, TaskMonitor monitor, MessageLog log)
throws IOException, OmfException {
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");
}
OmfFileHeader header = (OmfFileHeader)record;
OmfFileHeader header = (OmfFileHeader) record;
Object lastDataBlock = null;
while((record.getRecordType() & (byte)0xfe) != OmfRecord.MODEND) {
if (monitor.isCancelled()) {
break; // Return what we have
}
while (true) {
record = OmfRecord.readRecord(reader);
byte type = record.getRecordType();
type &= 0xfe; // Mask off the least significant bit
switch(type) {
case COMENT:
byte commentClass = ((OmfCommentRecord)record).getCommentClass();
if (monitor.isCancelled()) {
break;
}
if (record instanceof OmfModuleEnd) {
break;
}
if (record instanceof OmfCommentRecord comment) {
byte commentClass = comment.getCommentClass();
if (commentClass == OmfCommentRecord.COMMENT_CLASS_TRANSLATOR) {
header.translator = ((OmfCommentRecord)record).getValue();
header.translator = comment.getValue();
}
else if (commentClass == OmfCommentRecord.COMMENT_CLASS_LIBMOD) {
header.libModuleName = ((OmfCommentRecord)record).getValue();
header.libModuleName = comment.getValue();
}
break;
case MODEND:
// header.endModule = (OmfModuleEnd)record;
// We are not currently examining the end module record
break;
case COMDEF:
case LCOMDEF:
header.evaluateComdef((OmfComdefRecord)record);
header.externsymbols.add((OmfExternalSymbol)record);
break;
case LEXTDEF:
case EXTDEF:
header.externsymbols.add((OmfExternalSymbol)record);
break;
case PUBDEF:
case LPUBDEF:
header.symbols.add((OmfSymbolRecord)record);
break;
case LINNUM:
break; // Not saving this information currently
case LNAMES:
((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;
}
else if (record instanceof OmfComdefRecord comdef) {
header.evaluateComdef(comdef);
header.externsymbols.add((OmfExternalSymbol) record);
}
else if (record instanceof OmfExternalSymbol external) {
header.externsymbols.add(external);
}
else if (record instanceof OmfSymbolRecord symbol) {
header.symbols.add(symbol);
}
else if (record instanceof OmfNamesRecord names) {
names.appendNames(header.nameList); // Keep names, otherwise don't save record
}
else if (record instanceof OmfSegmentHeader seghead) {
header.segments.add(seghead);
}
else if (record instanceof OmfGroupRecord group) {
header.groups.add(group);
}
else if (record instanceof OmfFixupRecord fixuprec) {
fixuprec.setDataBlock(lastDataBlock);
header.fixup.add(fixuprec);
break;
case LEDATA:
OmfEnumeratedData enumheader = (OmfEnumeratedData)record;
}
else if (record instanceof OmfEnumeratedData enumheader) {
header.addEnumeratedBlock(enumheader);
lastDataBlock = enumheader;
break;
case LIDATA:
OmfIteratedData iterheader = (OmfIteratedData)record;
if (iterheader.getSegmentIndex() <= 0 || iterheader.getSegmentIndex() > header.segments.size()) {
}
else if (record instanceof OmfIteratedData iterheader) {
if (iterheader.getSegmentIndex() <= 0 ||
iterheader.getSegmentIndex() > header.segments.size()) {
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);
lastDataBlock = iterheader;
break;
default:
// Should never reach here
}
else if (record instanceof OmfUnsupportedRecord) {
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;
}
/**
* Assign a load image address to each segment. Follow OMF rules for grouping and ordering
* 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
* @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
for (int i = 0; i < groups.size(); ++i) {
OmfGroupRecord group = groups.get(i);
@ -396,14 +396,15 @@ public class OmfFileHeader extends OmfRecord {
try {
OmfSegmentHeader segment = segments.get(index - 1);
startAddress = segment.relocateSegment(startAddress, -1);
} catch (IndexOutOfBoundsException ex) {
}
catch (IndexOutOfBoundsException ex) {
throw new OmfException(ex.getMessage());
}
}
}
// 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);
if (segment.getStartAddress() != -1) {
continue; // Address already assigned
@ -411,7 +412,7 @@ public class OmfFileHeader extends OmfRecord {
startAddress = segment.relocateSegment(startAddress, -1);
// 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);
if (combineSeg.getStartAddress() != -1) {
continue;
@ -426,19 +427,19 @@ public class OmfFileHeader extends OmfRecord {
if (C == 0) {
continue; // Private segment
}
if (C==2 || C==4 || C==7) {
if (C == 2 || C == 4 || C == 7) {
startAddress = combineSeg.relocateSegment(startAddress, -1);
}
else if (C==5) {
else if (C == 5) {
startAddress = combineSeg.relocateSegment(startAddress, 1);
}
else {
throw new OmfException("Combine type not supported");
}
}
}
}
}
/**
* Check that the file has the specific OMF magic number
* @param reader accesses the bytes of the file
@ -457,13 +458,17 @@ public class OmfFileHeader extends OmfRecord {
}
return true;
}
/**
* Create a reader for a specific OMF file
* @param provider is the underlying ByteProvider
* @return the new reader
*/
public static BinaryReader createReader(ByteProvider provider) {
return new BinaryReader(provider,true/* Always little endian */);
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 OmfEnumeratedData lastLEData = null;
private OmfIteratedData lastLIData = null;
public OmfFixupRecord(BinaryReader reader) throws IOException {
ArrayList<Subrecord> subreclist = new ArrayList<Subrecord>();
boolean hasBigFields = ((getRecordType() & 1)!=0);
boolean hasBigFields = ((getRecordType() & 1) != 0);
readRecordHeader(reader);
long max = reader.getPointerIndex() + getRecordLength() - 1;
while(reader.getPointerIndex() < max) {
while (reader.getPointerIndex() < max) {
byte peek = reader.peekNextByte();
if ((peek & 0x80)==0) {
if ((peek & 0x80) == 0) {
ThreadSubrecord subrec = ThreadSubrecord.readThreadSubrecord(reader, hasBigFields);
subreclist.add(subrec);
}
@ -49,18 +49,18 @@ public class OmfFixupRecord extends OmfRecord {
subreclist.toArray(subrecs);
readCheckSumByte(reader);
}
public void setDataBlock(Object last) {
if (last instanceof OmfEnumeratedData) {
lastLEData = (OmfEnumeratedData)last;
lastLEData = (OmfEnumeratedData) last;
lastLIData = null;
}
else {
lastLIData = (OmfIteratedData)last;
lastLIData = (OmfIteratedData) last;
lastLEData = null;
}
}
public Subrecord[] getSubrecords() {
return subrecs;
}
@ -78,9 +78,9 @@ public class OmfFixupRecord extends OmfRecord {
public Address locAddress; // Location of data to be patched
public boolean M; // true for segment-relative, false for self-relative
public int locationType;
public FixupState(OmfFileHeader header,ArrayList<OmfSymbol> externsyms,Language lang) {
for(int i=0;i<4;++i) {
public FixupState(OmfFileHeader header, ArrayList<OmfSymbol> externsyms, Language lang) {
for (int i = 0; i < 4; ++i) {
frameThreads[i] = null;
targetThreads[i] = null;
}
@ -89,26 +89,26 @@ public class OmfFixupRecord extends OmfRecord {
externals = externsyms;
language = lang;
}
public void clear() {
targetState = -1;
locAddress = null;
locationType = -1;
}
}
public static class Subrecord {
private boolean isThread;
public Subrecord(boolean isthread) {
isThread = isthread;
}
public boolean isThread() {
return isThread;
}
}
public static class ThreadSubrecord extends Subrecord {
private byte type;
private int index;
@ -116,42 +116,47 @@ public class OmfFixupRecord extends OmfRecord {
public ThreadSubrecord() {
super(true);
}
public int getMethod() {
return (type>>2) & 7;
return (type >> 2) & 7;
}
public int getIndex() {
return index;
}
public boolean isFrameThread() {
return ((type>>6)&1)!=0;
return ((type >> 6) & 1) != 0;
}
public int getThreadNum() {
return (type & 3);
}
public void updateState(FixupState state) {
if (isFrameThread())
if (isFrameThread()) {
state.frameThreads[getThreadNum()] = this;
else
}
else {
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();
thread.type = reader.readNextByte();
int method = thread.getMethod();
if (method < 4)
if (method < 4) {
thread.index = OmfRecord.readInt1Or2(reader, hasBigFields);
else
}
else {
thread.index = -1;
}
return thread;
}
}
public static class FixupTarget {
private byte fixData;
private int frameDatum;
@ -159,28 +164,28 @@ public class OmfFixupRecord extends OmfRecord {
private int targetDisplacement;
public boolean isFrameThread() {
return ((fixData>>7)&1)!=0;
return ((fixData >> 7) & 1) != 0;
}
public boolean isTargetThread() {
return ((fixData>>3)&1)!=0;
return ((fixData >> 3) & 1) != 0;
}
public int getFrameMethod() {
return ((fixData>>4)&7);
return ((fixData >> 4) & 7);
}
public int getP() {
int res = (fixData >>2)&1;
int res = (fixData >> 2) & 1;
return res;
}
public void resolveFrame(FixupState state) throws OmfException {
int method;
int index;
if (isFrameThread()) {
// Frame datum from a thread
int threadnum = ((fixData>>4)&3);
int threadnum = ((fixData >> 4) & 3);
ThreadSubrecord subrec = state.frameThreads[threadnum];
method = subrec.getMethod();
index = subrec.getIndex();
@ -189,31 +194,33 @@ public class OmfFixupRecord extends OmfRecord {
method = getFrameMethod();
index = frameDatum;
}
switch(method) {
case 0: // Index is for a segment
state.frameState = state.header.resolveSegment(index).getFrameDatum();
break;
case 1: // Index is for a group
state.frameState = state.groups.get(index-1).getFrameDatum();
break;
case 2: // Index is for an external symbol
state.frameState = state.externals.get(index-1).getFrameDatum();
break;
case 4: // Segment Index grabbed from datablock
if (state.currentFixupRecord.lastLEData != null)
index = state.currentFixupRecord.lastLEData.getSegmentIndex();
else
index = state.currentFixupRecord.lastLIData.getSegmentIndex();
state.frameState = state.header.resolveSegment(index).getFrameDatum();
break;
case 5: // Frame determined by target
// TODO: Fill this in properly
break;
default:
state.frameState = -1; // Indicate an error condition
switch (method) {
case 0: // Index is for a segment
state.frameState = state.header.resolveSegment(index).getFrameDatum();
break;
case 1: // Index is for a group
state.frameState = state.groups.get(index - 1).getFrameDatum();
break;
case 2: // Index is for an external symbol
state.frameState = state.externals.get(index - 1).getFrameDatum();
break;
case 4: // Segment Index grabbed from datablock
if (state.currentFixupRecord.lastLEData != null) {
index = state.currentFixupRecord.lastLEData.getSegmentIndex();
}
else {
index = state.currentFixupRecord.lastLIData.getSegmentIndex();
}
state.frameState = state.header.resolveSegment(index).getFrameDatum();
break;
case 5: // Frame determined by target
// TODO: Fill this in properly
break;
default:
state.frameState = -1; // Indicate an error condition
}
}
public void resolveTarget(FixupState state) throws OmfException {
int method;
int index;
@ -230,67 +237,68 @@ public class OmfFixupRecord extends OmfRecord {
index = targetDatum;
}
switch(method) {
case 0: // Index is for a segment
state.targetState = state.header.resolveSegment(index).getStartAddress();
state.targetState += targetDisplacement;
break;
case 1: // Index is for a group
state.targetState = state.groups.get(index-1).getStartAddress();
state.targetState += targetDisplacement;
break;
case 2: // Index is for an external symbol
state.targetState = state.externals.get(index-1).getAddress().getOffset();
state.targetState += targetDisplacement;
break;
// case 3: // Not supported by many linkers
case 4: // segment only, no displacement
state.targetState = state.header.resolveSegment(index).getStartAddress();
break;
case 5: // group only, no displacement
state.targetState = state.groups.get(index-1).getStartAddress();
break;
case 6: // external only, no displacement
state.targetState = state.externals.get(index-1).getAddress().getOffset();
break;
default:
state.targetState = -1; // This indicates an unresolved target
switch (method) {
case 0: // Index is for a segment
state.targetState = state.header.resolveSegment(index).getStartAddress();
state.targetState += targetDisplacement;
break;
case 1: // Index is for a group
state.targetState = state.groups.get(index - 1).getStartAddress();
state.targetState += targetDisplacement;
break;
case 2: // Index is for an external symbol
state.targetState = state.externals.get(index - 1).getAddress().getOffset();
state.targetState += targetDisplacement;
break;
// case 3: // Not supported by many linkers
case 4: // segment only, no displacement
state.targetState = state.header.resolveSegment(index).getStartAddress();
break;
case 5: // group only, no displacement
state.targetState = state.groups.get(index - 1).getStartAddress();
break;
case 6: // external only, no displacement
state.targetState = state.externals.get(index - 1).getAddress().getOffset();
break;
default:
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.fixData = reader.readNextByte();
if ((fixupTarget.fixData & 0x80)==0) { // F=0 (explicit frame method (and datum))
int method = (fixupTarget.fixData >> 4)&7;
if (method <3) {
if ((fixupTarget.fixData & 0x80) == 0) { // F=0 (explicit frame method (and datum))
int method = (fixupTarget.fixData >> 4) & 7;
if (method < 3) {
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);
}
if ((fixupTarget.fixData & 0x04)==0) // P=0
if ((fixupTarget.fixData & 0x04) == 0) // P=0
fixupTarget.targetDisplacement = OmfRecord.readInt2Or4(reader, hasBigFields);
return fixupTarget;
}
}
public static class FixupSubrecord extends Subrecord {
private byte lobyte; // lo-byte of location
private byte hibyte; // hi-byte of location
private FixupTarget target;
public FixupSubrecord() {
super(false);
}
public void resolveFixup(FixupState state) throws OmfException {
target.resolveTarget(state); // Resolve target first as frame may need to reference results
target.resolveFrame(state);
state.M = ((lobyte>>6)&1)!=0;
state.locationType = ((lobyte>>2)&0xf);
state.M = ((lobyte >> 6) & 1) != 0;
state.locationType = ((lobyte >> 2) & 0xf);
int dataRecordOffset = lobyte & 3;
dataRecordOffset <<= 8;
dataRecordOffset |= (hibyte) & 0xff;
@ -305,15 +313,16 @@ public class OmfFixupRecord extends OmfRecord {
segIndex = state.currentFixupRecord.lastLIData.getSegmentIndex();
}
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.lobyte = reader.readNextByte();
fixupSubrecord.hibyte = reader.readNextByte();
fixupSubrecord.target = FixupTarget.readFixupTarget(reader, hasBigFields);
return fixupSubrecord;
}
}
}
}

View file

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

View file

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

View file

@ -15,12 +15,12 @@
*/
package ghidra.app.util.bin.format.omf;
import ghidra.app.util.bin.BinaryReader;
import ghidra.util.task.TaskMonitor;
import java.io.IOException;
import java.util.ArrayList;
import ghidra.app.util.bin.BinaryReader;
import ghidra.util.task.TaskMonitor;
public class OmfLibraryRecord extends OmfRecord {
private int pageSize; // All archive members must start on a page boundary of this size
private long dictionaryOffset;
@ -35,7 +35,7 @@ public class OmfLibraryRecord extends OmfRecord {
public String translator;
public String machineName;
}
public OmfLibraryRecord(BinaryReader reader) throws IOException {
readRecordHeader(reader);
pageSize = recordLength + 3;
@ -44,62 +44,75 @@ public class OmfLibraryRecord extends OmfRecord {
flags = reader.readNextByte();
// No checksum byte (just padding)
}
public int getPageSize() {
return pageSize;
}
public ArrayList<MemberHeader> getMemberHeaders() {
return members;
}
public static boolean checkMagicNumer(BinaryReader reader) throws IOException {
byte type = reader.readNextByte();
if (type != (byte)0xF0)
if (type != (byte) 0xF0) {
return false;
}
int pageSize = (reader.readNextShort() & 0xffff) + 3;
// Make sure page size is a power of 2, 2^4 - 2^15
int count = 0;
int mask = pageSize;
while((mask & 1)==0) {
while ((mask & 1) == 0) {
count += 1;
mask >>>= 1;
}
if (mask != 1) return false; // Test if this is a power of 2
if (count < 4) return false;
if (count > 15) return false;
if (mask != 1) {
return false; // Test if this is a power of 2
}
if (count < 4) {
return false;
}
if (count > 15) {
return false;
}
reader.align(pageSize);
type = reader.readNextByte();
if ((type & 0xfc) != 0x80) return false;
if ((type & 0xfc) != 0x80) {
return false;
}
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;
byte type = reader.peekNextByte();
if (type != (byte)0xF0)
if (type != (byte) 0xF0) {
throw new IOException("Not an OMF Library record");
}
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
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();
curheader.payloadOffset = reader.getPointerIndex();
OmfFileHeader fileheader;
try {
fileheader = OmfFileHeader.scan(reader, monitor,false);
} catch (OmfException e) {
fileheader = OmfFileHeader.scan(reader, monitor, false);
}
catch (OmfException e) {
throw new IOException("Could not parse individual object file within archive");
}
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.machineName = fileheader.getMachineName();
curheader.translator = fileheader.getTranslator();
curheader.size = (int)(reader.getPointerIndex() - curheader.payloadOffset);
res.members.add(curheader);
curheader.size = (int) (reader.getPointerIndex() - curheader.payloadOffset);
res.members.add(curheader);
reader.align(res.pageSize); // Skip padding to get to next page boundary
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
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (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 {
private byte moduleType;
private OmfFixupRecord.FixupTarget startAddress;
public OmfModuleEnd(BinaryReader reader) throws IOException {
readRecordHeader(reader);
moduleType = reader.readNextByte();
if (hasStartAddress())
startAddress = OmfFixupRecord.FixupTarget.readFixupTarget(reader,hasBigFields());
if (hasStartAddress()) {
startAddress = OmfFixupRecord.FixupTarget.readFixupTarget(reader, hasBigFields());
}
readCheckSumByte(reader);
}
public boolean isMainProgramModule() {
return ((moduleType & 0x80)!=0);
return ((moduleType & 0x80) != 0);
}
public boolean hasStartAddress() {
return ((moduleType & 0x40)!=0);
return ((moduleType & 0x40) != 0);
}
}

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (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 {
private ArrayList<String> name;
public OmfNamesRecord(BinaryReader reader) throws IOException {
readRecordHeader(reader);
long max = reader.getPointerIndex() + getRecordLength() -1;
long max = reader.getPointerIndex() + getRecordLength() - 1;
name = new ArrayList<String>();
while(reader.getPointerIndex() < max) {
while (reader.getPointerIndex() < max) {
String nm = OmfRecord.readString(reader);
name.add(nm);
}
readCheckSumByte(reader);
}
public void appendNames(ArrayList<String> namelist) {
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
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (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;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import ghidra.app.util.bin.BinaryReader;
public abstract class OmfRecord {
public final static byte THEADR = (byte)0x80;
public final static byte LHEADR = (byte)0x82;
public final static byte COMENT = (byte)0x88;
public final static byte MODEND = (byte)0x8A;
public final static byte EXTDEF = (byte)0x8C;
public final static byte PUBDEF = (byte)0x90;
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 COMDEF = (byte)0xB0;
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 RHEADR = (byte) 0x6E; // Obsolete
public final static byte REGINT = (byte) 0x70; // Obsolete
public final static byte REDATA = (byte) 0x72; // Obsolete
public final static byte RIDATA = (byte) 0x74; // Obsolete
public final static byte OVLDEF = (byte) 0x76; // Obsolete
public final static byte ENDREC = (byte) 0x78; // Obsolete
public final static byte BLKDEF = (byte) 0x7A; // Obsolete
public final static byte BLKEND = (byte) 0x7C; // Obsolete
public final static byte DEBSYM = (byte) 0x7E; // Obsolete
public final static byte THEADR = (byte) 0x80;
public final static byte LHEADR = (byte) 0x82;
public final static byte PEDATA = (byte) 0x84; // Obsolete
public final static byte PIDATA = (byte) 0x86; // Obsolete
public final static byte COMENT = (byte) 0x88;
public final static byte MODEND = (byte) 0x8A;
public final static byte EXTDEF = (byte) 0x8C;
public final static byte TYPDEF = (byte) 0x8E; // Obsolete
public final static byte PUBDEF = (byte) 0x90;
public final static byte LOCSYM = (byte) 0x92; // Obsolete
public final static byte LINNUM = (byte) 0x94;
public final static byte LNAMES = (byte) 0x96;
public final static byte SEGDEF = (byte) 0x98;
public final static byte GRPDEF = (byte) 0x9A;
public final static byte FIXUPP = (byte) 0x9C;
public final static byte LEDATA = (byte) 0xA0;
public final static byte LIDATA = (byte) 0xA2;
public final static byte LIBHED = (byte) 0xA4; // Obsolete
public final static byte LIBNAM = (byte) 0xA6; // Obsolete
public final static byte LIBLOC = (byte) 0xA8; // Obsolete
public final static byte LIBDIC = (byte) 0xAA; // Obsolete
public final static byte COMDEF = (byte) 0xB0;
public final static byte BAKPAT = (byte) 0xB2;
public final static byte LEXTDEF = (byte) 0xB4;
public final static byte LPUBDEF = (byte) 0xB6;
public final static byte LCOMDEF = (byte) 0xB8;
public final static byte CEXTDEF = (byte) 0xBC;
public final static byte COMDAT = (byte) 0xC2;
public final static byte LINSYM = (byte) 0xC4;
public final static byte ALIAS = (byte) 0xC6;
public final static byte NBKPAT = (byte) 0xC8;
public final static byte LLNAMES = (byte) 0xCA;
public final static byte VERNUM = (byte) 0xCC;
public final static byte VENDEXT = (byte) 0xCE;
public final static byte START = (byte) 0xF0;
public final static byte END = (byte) 0xF1;
protected byte recordType;
protected int recordLength;
protected long recordOffset;
protected byte checkSum;
public byte getRecordType() {
return recordType;
}
public int getRecordLength() {
return recordLength;
}
public long getRecordOffset() {
return recordOffset;
}
public void readRecordHeader(BinaryReader reader) throws IOException {
recordOffset = reader.getPointerIndex();
recordType = reader.readNextByte();
recordLength = reader.readNextShort() & 0xffff;
}
public void readCheckSumByte(BinaryReader reader) throws IOException {
checkSum = reader.readNextByte();
}
public byte calcCheckSum(BinaryReader reader) throws IOException {
byte res = reader.readNextByte();
res += reader.readNextByte();
res += reader.readNextByte(); // Sum the record header bytes
for(int i=0;i<recordLength;++i)
for (int i = 0; i < recordLength; ++i)
res += reader.readNextByte();
return res;
}
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);
}
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)
return (reader.readNextShort() & 0xffff);
return (reader.readNextShort() & 0xffff);
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)
return reader.readNextInt();
return (reader.readNextShort() & 0xffff);
}
public static int readIndex(BinaryReader reader) throws IOException {
int indexWord;
byte firstByte = reader.readNextByte();
if ((firstByte & 0x80)!=0)
if ((firstByte & 0x80) != 0) {
indexWord = (firstByte & 0x7f) * 0x100 + (reader.readNextByte() & 0xff);
else
}
else {
indexWord = firstByte;
}
return indexWord;
}
public static OmfRecord readRecord(BinaryReader reader) throws IOException, OmfException {
OmfRecord res = null;
byte type = reader.peekNextByte();
type &= 0xfe; // Mask off the least significant bit
switch(type) {
case THEADR:
case LHEADR:
res = new OmfFileHeader(reader);
break;
case COMENT:
res = new OmfCommentRecord(reader);
break;
case MODEND:
res = new OmfModuleEnd(reader);
break;
case EXTDEF:
res = new OmfExternalSymbol(reader,false);
break;
case PUBDEF:
res = new OmfSymbolRecord(reader,false);
break;
case LINNUM:
res = new OmfLineNumberRecord(reader);
break;
case LNAMES:
res = new OmfNamesRecord(reader);
break;
case SEGDEF:
res = new OmfSegmentHeader(reader);
break;
case GRPDEF:
res = new OmfGroupRecord(reader);
break;
case FIXUPP:
res = new OmfFixupRecord(reader);
break;
case LEDATA:
res = new OmfEnumeratedData(reader);
break;
case LIDATA:
res = new OmfIteratedData(reader);
break;
case COMDEF:
res = new OmfComdefRecord(reader,false);
break;
case LEXTDEF:
res = new OmfExternalSymbol(reader,true);
break;
case LPUBDEF:
res = new OmfSymbolRecord(reader,true);
break;
case LCOMDEF:
res = new OmfComdefRecord(reader,true);
break;
default:
throw new OmfException("Unrecognized record type");
}
return res;
type &= 0xfe; // Mask off the least significant bit (16/32 bit flag)
return switch (type) {
case THEADR:
case LHEADR:
yield new OmfFileHeader(reader);
case COMENT:
yield new OmfCommentRecord(reader);
case MODEND:
yield new OmfModuleEnd(reader);
case EXTDEF:
yield new OmfExternalSymbol(reader, false);
case PUBDEF:
yield new OmfSymbolRecord(reader, false);
case LNAMES:
yield new OmfNamesRecord(reader);
case SEGDEF:
yield new OmfSegmentHeader(reader);
case GRPDEF:
yield new OmfGroupRecord(reader);
case FIXUPP:
yield new OmfFixupRecord(reader);
case LEDATA:
yield new OmfEnumeratedData(reader);
case LIDATA:
yield new OmfIteratedData(reader);
case COMDEF:
yield new OmfComdefRecord(reader, false);
case LEXTDEF:
yield new OmfExternalSymbol(reader, true);
case LPUBDEF:
yield new OmfSymbolRecord(reader, true);
case LCOMDEF:
yield new OmfComdefRecord(reader, true);
case RHEADR:
case REGINT:
case REDATA:
case RIDATA:
case OVLDEF:
case ENDREC:
case BLKDEF:
case BLKEND:
case DEBSYM:
case LINNUM:
case PEDATA:
case PIDATA:
case LIBHED:
case LIBNAM:
case LIBLOC:
case LIBDIC:
yield new OmfObsoleteRecord(reader);
case LOCSYM:
case TYPDEF:
case CEXTDEF:
case COMDAT:
case LINSYM:
case ALIAS:
case BAKPAT:
case NBKPAT:
case LLNAMES:
case VERNUM:
case VENDEXT:
yield new OmfUnsupportedRecord(reader);
default:
yield new OmfUnknownRecord(reader);
};
}
/**
* Read the OMF string format, 1-byte length, followed by that many ascii characters
* @param reader
* @return
* @throws IOException
* Read the OMF string format: 1-byte length, followed by that many ascii characters
*
* @param reader A {@link BinaryReader} positioned at the start of the string
* @return the read OMF string
* @throws IOException if an IO-related error occurred
*/
public static String readString(BinaryReader reader) throws IOException {
int count = reader.readNextByte() & 0xff;
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 ArrayList<OmfData> dataBlocks = new ArrayList<OmfData>();
OmfSegmentHeader(int num,int datatype) {
OmfSegmentHeader(int num, int datatype) {
// generate a special Borland header
segAttr = (byte)0xa9;
segAttr = (byte) 0xa9;
segmentLength = 0;
segmentNameIndex = 0;
classNameIndex = 0;
@ -62,7 +62,7 @@ public class OmfSegmentHeader extends OmfRecord {
else {
segmentName = "EXTRA_";
}
segmentName = segmentName+Integer.toString(num);
segmentName = segmentName + Integer.toString(num);
if (datatype == 1) {
// Treat as a text segment
className = "TEXT";
@ -79,7 +79,7 @@ public class OmfSegmentHeader extends OmfRecord {
isExecutable = false;
}
}
public OmfSegmentHeader(BinaryReader reader) throws IOException {
readRecordHeader(reader);
boolean hasBigFields = hasBigFields();
@ -88,15 +88,15 @@ public class OmfSegmentHeader extends OmfRecord {
if (A == 0) {
frameNumber = reader.readNextShort() & 0xffff;
offset = reader.readNextByte() & 0xff;
vma = (long)frameNumber + offset;
vma = (long) frameNumber + offset;
}
segmentLength = OmfRecord.readInt2Or4(reader, hasBigFields) & 0xffffffffL;
segmentNameIndex = OmfRecord.readIndex(reader);
classNameIndex = OmfRecord.readIndex(reader);
overlayNameIndex = OmfRecord.readIndex(reader);
readCheckSumByte(reader);
int B = (segAttr>>1) & 1;
if (B==1) { // Ignore the segmentLength field
int B = (segAttr >> 1) & 1;
if (B == 1) { // Ignore the segmentLength field
if (getRecordType() == OmfRecord.SEGDEF) {
segmentLength = 0x10000L; // Exactly 64K segment
}
@ -105,28 +105,28 @@ public class OmfSegmentHeader extends OmfRecord {
}
}
}
/**
* @return true if this is a code segment
*/
public boolean isCode() {
return isCode;
}
/**
* @return true if this segment is readable
*/
public boolean isReadable() {
return isReadable;
}
/**
* @return true if this segment is writable
*/
public boolean isWritable() {
return isWritable;
}
/**
* @return true if this segment is executable
*/
@ -140,7 +140,7 @@ public class OmfSegmentHeader extends OmfRecord {
public int getFrameDatum() {
return 0; // TODO: Need to fill in a real segment selector
}
/**
* @param language is the Program language for this binary
* @return the starting Address for this segment
@ -150,26 +150,27 @@ public class OmfSegmentHeader extends OmfRecord {
if (isCode) {
addrSpace = language.getDefaultSpace();
} else {
}
else {
addrSpace = language.getDefaultDataSpace();
}
return addrSpace.getAddress(vma);
return addrSpace.getAddress(vma);
}
/**
* @return the name of this segment
*/
public String getName() {
return segmentName;
}
/**
* @return the class name of this segment
*/
public String getClassName() {
return className;
}
/**
* @return the name of the overlay, or the empty string
*/
@ -183,21 +184,21 @@ public class OmfSegmentHeader extends OmfRecord {
public long getStartAddress() {
return vma;
}
/**
* @return the length of the segment in bytes
*/
public long getSegmentLength() {
return segmentLength;
}
/**
* @return the alignment required for this segment
*/
public int getAlignment() {
return (segAttr >> 5) & 0x7;
}
/**
* @return special combining rules for this segment
*/
@ -223,7 +224,7 @@ public class OmfSegmentHeader extends OmfRecord {
protected void sortData() {
Collections.sort(dataBlocks);
}
/**
* Get an InputStream that reads in the raw data for this segment
* @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 {
return new SectionStream(reader, log);
}
/**
* Given the first possible address where this segment can reside, relocate the
* segment based on this address and alignment considerations.
@ -244,35 +245,35 @@ public class OmfSegmentHeader extends OmfRecord {
* @throws OmfException for bad alignment information
*/
protected long relocateSegment(long firstValidAddress, int alignOverride) throws OmfException {
int align = getAlignment();
int align = getAlignment();
if (alignOverride >= 0) {
align = alignOverride;
}
switch(align) {
case 0: // Absolute segment, not relocatable
throw new OmfException("Trying to relocate an absolute segment");
case 1: // Byte aligned
break; // Keep the first valid address
case 2: // 2-byte aligned
firstValidAddress = (firstValidAddress+1 ) & 0xfffffffffffffffeL;
break;
case 3: // 16-byte aligned
firstValidAddress = (firstValidAddress+15) & 0xfffffffffffffff0L;
break;
case 4: // "page" aligned, assume 4096
firstValidAddress = (firstValidAddress+4095) & 0xfffffffffffff000L;
break;
case 5: // 4-byte aligned
firstValidAddress = (firstValidAddress+3) & 0xfffffffffffffffcL;
break;
default:
throw new OmfException("Unsupported alignment type");
switch (align) {
case 0: // Absolute segment, not relocatable
throw new OmfException("Trying to relocate an absolute segment");
case 1: // Byte aligned
break; // Keep the first valid address
case 2: // 2-byte aligned
firstValidAddress = (firstValidAddress + 1) & 0xfffffffffffffffeL;
break;
case 3: // 16-byte aligned
firstValidAddress = (firstValidAddress + 15) & 0xfffffffffffffff0L;
break;
case 4: // "page" aligned, assume 4096
firstValidAddress = (firstValidAddress + 4095) & 0xfffffffffffff000L;
break;
case 5: // 4-byte aligned
firstValidAddress = (firstValidAddress + 3) & 0xfffffffffffffffcL;
break;
default:
throw new OmfException("Unsupported alignment type");
}
vma = firstValidAddress;
firstValidAddress = vma + segmentLength;
return firstValidAddress;
}
/**
* 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
@ -308,7 +309,7 @@ public class OmfSegmentHeader extends OmfRecord {
}
overlayName = nameList.get(overlayNameIndex - 1);
}
// Once we know the class name, we can make some educated guesses about read/write/exec permissions
isReadable = true;
if (className.equals("CODE") || className.equals("code")) {
@ -322,7 +323,7 @@ public class OmfSegmentHeader extends OmfRecord {
isExecutable = false;
}
}
/**
* Add an explicit data-block to this segment.
* @param rec is the data-block
@ -330,7 +331,7 @@ public class OmfSegmentHeader extends OmfRecord {
protected void addEnumeratedData(OmfEnumeratedData rec) {
dataBlocks.add(rec);
}
/**
* Add an explicit data-block to this segment that might extend
* the length of this segment. Borland compilers in particular produce
@ -344,7 +345,7 @@ public class OmfSegmentHeader extends OmfRecord {
}
dataBlocks.add(rec);
}
/**
* Add a compressed-form data-block to this segment
* @param rec is the data-block
@ -352,7 +353,7 @@ public class OmfSegmentHeader extends OmfRecord {
protected void addIteratedData(OmfIteratedData rec) {
dataBlocks.add(rec);
}
/**
* 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,
@ -365,7 +366,7 @@ public class OmfSegmentHeader extends OmfRecord {
private byte[] buffer; // Current buffer
private int bufferpointer; // current index into buffer
private int dataUpNext; // Index of next data section OmfIteratedData/OmfEnumeratedData to be buffered
public SectionStream(BinaryReader reader, MessageLog log) throws IOException {
super();
this.reader = reader;
@ -376,7 +377,7 @@ public class OmfSegmentHeader extends OmfRecord {
establishNextBuffer();
}
}
/**
* Fill the next buffer of bytes being provided by this stream.
* @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
long size = data.getDataOffset() - pointer;
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];
for(int i=0;i<size;++i) {
buffer = new byte[(int) size];
for (int i = 0; i < size; ++i) {
buffer[i] = 0;
}
bufferpointer = 0;
@ -416,15 +418,15 @@ public class OmfSegmentHeader extends OmfRecord {
// We may have filler after the last block
long size = segmentLength - pointer;
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];
for(int i=0;i<size;++i) {
buffer = new byte[(int) size];
for (int i = 0; i < size; ++i) {
buffer[i] = 0;
}
bufferpointer = 0;
bufferpointer = 0;
}
@Override
public int read() throws IOException {
if (pointer < segmentLength) {
@ -443,6 +445,6 @@ public class OmfSegmentHeader extends OmfRecord {
}
return -1;
}
}
}

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (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 dataType; // 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 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;
typeIndex = type;
offset = off;
dataType = dT;
byteLength = bL;
}
public String getName() {
return symbolName;
}
public int getDataType() {
return dataType;
}
public long getOffset() {
return offset;
}
public int getSegmentRef() {
return segmentRef;
}
public void setSegmentRef(int val) {
segmentRef = val;
}
public void setAddress(Address addr) {
address = addr;
}
public Address getAddress() {
return address;
}
public int getFrameDatum() {
return 0; // This is currently unused
}

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (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 boolean isStatic;
private OmfSymbol[] symbol;
public OmfSymbolRecord(BinaryReader reader,boolean isStatic) throws IOException {
public OmfSymbolRecord(BinaryReader reader, boolean isStatic) throws IOException {
this.isStatic = isStatic;
readRecordHeader(reader);
long max = reader.getPointerIndex() + getRecordLength() - 1;
boolean hasBigFields = hasBigFields();
baseGroupIndex = OmfRecord.readIndex(reader);
baseSegmentIndex = OmfRecord.readIndex(reader);
if (baseSegmentIndex == 0)
if (baseSegmentIndex == 0) {
baseFrame = reader.readNextShort() & 0xffff;
}
ArrayList<OmfSymbol> symbollist = new ArrayList<OmfSymbol>();
while(reader.getPointerIndex() < max) {
while (reader.getPointerIndex() < max) {
String name = OmfRecord.readString(reader);
long offset = OmfRecord.readInt2Or4(reader, hasBigFields) & 0xffffffffL;
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);
}
readCheckSumByte(reader);
@ -54,19 +54,19 @@ public class OmfSymbolRecord extends OmfRecord {
public boolean isStatic() {
return isStatic;
}
public int getGroupIndex() {
return baseGroupIndex;
}
public int getSegmentIndex() {
return baseSegmentIndex;
}
public int numSymbols() {
return symbol.length;
}
public OmfSymbol getSymbol(int 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.InvalidInputException;
import ghidra.util.task.TaskMonitor;
import ghidra.util.task.TaskMonitorAdapter;
public class OmfLoader extends AbstractProgramWrapperLoader {
public final static String OMF_NAME = "Relocatable Object Module Format (OMF)";
@ -115,7 +114,7 @@ public class OmfLoader extends AbstractProgramWrapperLoader {
OmfFileHeader header = null;
BinaryReader reader = OmfFileHeader.createReader(provider);
try {
header = OmfFileHeader.parse(reader, monitor);
header = OmfFileHeader.parse(reader, monitor, log);
header.resolveNames();
header.sortSegmentDataBlocks();
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 header is the OMF file header
* @param program is the Program
* @param mbu is the block creation utility
* @param monitor is checked for cancellation
* @param log receives error messages
* @throws AddressOverflowException if the underlying data stream causes an address to wrap