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,7 +42,7 @@ 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);
@ -52,8 +52,9 @@ public class OmfComdefRecord extends OmfExternalSymbol {
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,8 +66,9 @@ 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

@ -46,6 +46,10 @@ public class OmfCommentRecord extends OmfRecord {
readCheckSumByte(reader);
}
public byte getCommentType() {
return commentType;
}
public byte getCommentClass() {
return commentClass;
}

View file

@ -31,8 +31,8 @@ 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);
}

View file

@ -15,11 +15,11 @@
*/
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;
@ -28,16 +28,16 @@ public class OmfExternalSymbol extends OmfRecord {
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);
}

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);
@ -131,11 +131,11 @@ public class OmfFileHeader extends OmfRecord {
*/
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);
@ -179,18 +179,18 @@ 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;
}
@ -201,11 +201,11 @@ 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);
}
}
@ -219,17 +219,17 @@ 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;
}
@ -238,9 +238,9 @@ public class OmfFileHeader extends OmfRecord {
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,36 +256,35 @@ 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;
@ -293,86 +292,86 @@ public class OmfFileHeader extends OmfRecord {
/**
* 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;
@ -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,10 +427,10 @@ 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 {
@ -464,6 +465,10 @@ public class OmfFileHeader extends OmfRecord {
* @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

@ -30,13 +30,13 @@ public class OmfFixupRecord extends OmfRecord {
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);
}
@ -52,11 +52,11 @@ public class OmfFixupRecord extends OmfRecord {
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;
}
}
@ -79,8 +79,8 @@ public class OmfFixupRecord extends OmfRecord {
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;
}
@ -118,7 +118,7 @@ public class OmfFixupRecord extends OmfRecord {
}
public int getMethod() {
return (type>>2) & 7;
return (type >> 2) & 7;
}
public int getIndex() {
@ -126,7 +126,7 @@ public class OmfFixupRecord extends OmfRecord {
}
public boolean isFrameThread() {
return ((type>>6)&1)!=0;
return ((type >> 6) & 1) != 0;
}
public int getThreadNum() {
@ -134,20 +134,25 @@ public class OmfFixupRecord extends OmfRecord {
}
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;
}
}
@ -159,19 +164,19 @@ 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;
}
@ -180,7 +185,7 @@ public class OmfFixupRecord extends OmfRecord {
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,28 +194,30 @@ 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
}
}
@ -230,47 +237,48 @@ 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;
}
@ -289,8 +297,8 @@ public class OmfFixupRecord extends OmfRecord {
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;
@ -308,7 +316,8 @@ public class OmfFixupRecord extends OmfRecord {
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();

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.
@ -35,12 +34,12 @@ public class OmfGroupRecord extends OmfRecord {
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);
}
@ -58,7 +57,7 @@ public class OmfGroupRecord extends OmfRecord {
/**
* 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
@ -82,10 +81,12 @@ public class OmfGroupRecord extends OmfRecord {
}
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);
}

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);
}
@ -100,21 +100,21 @@ public class OmfIteratedData extends OmfRecord implements OmfData {
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;
@ -55,50 +55,63 @@ public class OmfLibraryRecord extends OmfRecord {
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>();
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);
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.
@ -27,16 +26,17 @@ public class OmfModuleEnd extends OmfRecord {
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.
@ -26,9 +25,9 @@ public class OmfNamesRecord extends OmfRecord {
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);
}

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,29 +16,61 @@
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() {
@ -50,7 +81,12 @@ public abstract class OmfRecord {
return recordLength;
}
public long getRecordOffset() {
return recordOffset;
}
public void readRecordHeader(BinaryReader reader) throws IOException {
recordOffset = reader.getPointerIndex();
recordType = reader.readNextByte();
recordLength = reader.readNextShort() & 0xffff;
}
@ -63,27 +99,28 @@ public abstract class OmfRecord {
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);
@ -92,81 +129,123 @@ public abstract class OmfRecord {
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";
@ -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
}
@ -150,7 +150,8 @@ public class OmfSegmentHeader extends OmfRecord {
if (isCode) {
addrSpace = language.getDefaultSpace();
} else {
}
else {
addrSpace = language.getDefaultDataSpace();
}
return addrSpace.getAddress(vma);
@ -244,29 +245,29 @@ 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;
@ -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,10 +418,10 @@ 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;

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,11 +22,11 @@ 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;

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.
@ -28,22 +27,23 @@ public class OmfSymbolRecord extends OmfRecord {
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);

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