From e61f50f9e88b19363867e9dca5b3c8e5b00eabe0 Mon Sep 17 00:00:00 2001 From: Gravelbones Date: Wed, 28 Dec 2022 13:03:13 +0100 Subject: [PATCH 1/2] OMF format: Added handling of many record types (Closes #4856) --- .../util/bin/format/omf/OmfFileHeader.java | 145 +++++++----------- .../bin/format/omf/OmfLineNumberRecord.java | 55 ------- .../app/util/bin/format/omf/OmfRecord.java | 87 +++++++++-- .../bin/format/omf/OmfUnsupportedRecord.java | 52 +++++++ .../ghidra/app/util/opinion/OmfLoader.java | 2 +- 5 files changed, 183 insertions(+), 158 deletions(-) delete mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfLineNumberRecord.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfUnsupportedRecord.java diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfFileHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfFileHeader.java index fa2de8a9d4..53c4a22e9e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfFileHeader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfFileHeader.java @@ -21,6 +21,7 @@ import java.io.IOException; 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 { @@ -36,7 +37,7 @@ public class OmfFileHeader extends OmfRecord { private ArrayList symbols = new ArrayList(); private ArrayList fixup = new ArrayList(); private ArrayList 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 +45,7 @@ public class OmfFileHeader extends OmfRecord { readCheckSumByte(reader); isLittleEndian = reader.isLittleEndian(); } - + /** * This is usually the original source filename * @return the name @@ -52,7 +53,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 +61,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 +77,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 +98,7 @@ public class OmfFileHeader extends OmfRecord { public ArrayList getExtraSegments() { return extraSeg; } - + /** * @return the list of group records for this file */ @@ -111,21 +112,21 @@ public class OmfFileHeader extends OmfRecord { public ArrayList getExternalSymbols() { return externsymbols; } - + /** * @return the list of symbols exported by this file */ public ArrayList getPublicSymbols() { return symbols; } - + /** * @return the list of relocation records for this file */ public ArrayList getFixups() { return fixup; } - + /** * Sort the explicit data-blocks for each segment into address order. */ @@ -167,7 +168,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 @@ -193,7 +194,7 @@ public class OmfFileHeader extends OmfRecord { res = segments.get(index-1); return res; } - + /** * Resolve special names associated with each segment: segment, class, overlay names * and group: group name @@ -209,7 +210,7 @@ public class OmfFileHeader extends OmfRecord { 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 @@ -233,7 +234,7 @@ public class OmfFileHeader extends OmfRecord { } return segment; } - + private void evaluateComdef(OmfComdefRecord comdef) { OmfSymbol[] coms = comdef.getSymbols(); for (OmfSymbol sym : coms) { @@ -242,7 +243,7 @@ public class OmfFileHeader extends OmfRecord { int count = (extraSeg==null) ? 1 : extraSeg.size()+1; createOrFindBorlandSegment(count,dt); sym.setSegmentRef(count); - + } } } @@ -258,39 +259,30 @@ public class OmfFileHeader extends OmfRecord { */ 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) { + while(!(record instanceof OmfModuleEnd)) { if (monitor.isCancelled()) { break; // Return what we have } record = OmfRecord.readRecord(reader); - type = record.getRecordType(); - type &= 0xfe; // Mask off the least significant bit - if (initialCommentsOnly && (type != COMENT)) { - break; - } - switch(type) { - case COMENT: - byte commentClass = ((OmfCommentRecord)record).getCommentClass(); + if(record instanceof OmfCommentRecord coment) { + byte commentClass = coment.getCommentClass(); if (commentClass == OmfCommentRecord.COMMENT_CLASS_TRANSLATOR) { - header.translator = ((OmfCommentRecord)record).getValue(); + header.translator = coment.getValue(); } else if (commentClass == OmfCommentRecord.COMMENT_CLASS_LIBMOD) { - header.libModuleName = ((OmfCommentRecord)record).getValue(); + header.libModuleName = coment.getValue(); } + } else if(initialCommentsOnly) { break; - default: - break; // Skip most records } } return header; } - + /** * Parse the entire object file * @param reader is the byte stream @@ -299,85 +291,64 @@ public class OmfFileHeader extends OmfRecord { * @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; Object lastDataBlock = null; - - while((record.getRecordType() & (byte)0xfe) != OmfRecord.MODEND) { + + while(!(record instanceof OmfModuleEnd)) { if (monitor.isCancelled()) { break; // Return what we have } 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 (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); + } else if(record instanceof OmfModuleEnd) { + // We are not currently examining the end module record + // header.endModule = end; + } else if(record instanceof OmfComdefRecord comdef) { + header.evaluateComdef(comdef); 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 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; + } 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); segheader2.addIteratedData(iterheader); lastDataBlock = iterheader; - break; - default: - // Should never reach here + } else if(record instanceof OmfUnsupportedRecord unsupported) { + if(unsupported.doLogMessage()) + log.appendMsg(unsupported.getMessage()); } } return header; } - + /** * Assign a load image address to each segment. Follow OMF rules for grouping and ordering * the segments in memory. @@ -401,7 +372,7 @@ public class OmfFileHeader extends OmfRecord { } } } - + // Fill in any remaining segments for(int i=0;i linelist = new ArrayList(); - 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; - } - } -} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfRecord.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfRecord.java index 853c2ace93..c10dddec51 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfRecord.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfRecord.java @@ -21,12 +21,25 @@ import java.io.IOException; import ghidra.app.util.bin.BinaryReader; public abstract class OmfRecord { + public final static byte RHEADR = (byte)0x6E; // Obselete + public final static byte REGINT = (byte)0x70; // Obselete + public final static byte REDATA = (byte)0x72; // Obselete + public final static byte RIDATA = (byte)0x74; // Obselete + public final static byte OVLDEF = (byte)0x76; // Obselete + public final static byte ENDREC = (byte)0x78; // Obselete + public final static byte BLKDEF = (byte)0x7A; // Obselete + public final static byte BLKEND = (byte)0x7C; // Obselete + public final static byte DEBSYM = (byte)0x7E; // Obselete public final static byte THEADR = (byte)0x80; public final static byte LHEADR = (byte)0x82; + public final static byte PEDATA = (byte)0x84; // Obselete + public final static byte PIDATA = (byte)0x86; // Obselete 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; // Obselete public final static byte PUBDEF = (byte)0x90; + public final static byte LOCSYM = (byte)0x92; // Obselete public final static byte LINNUM = (byte)0x94; public final static byte LNAMES = (byte)0x96; public final static byte SEGDEF = (byte)0x98; @@ -34,10 +47,26 @@ public abstract class OmfRecord { 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; // Obselete + public final static byte LIBNAM = (byte)0xA6; // Obselete + public final static byte LIBLOC = (byte)0xA8; // Obselete + public final static byte LIBDIC = (byte)0xAA; // Obselete 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 byte checkSum; @@ -45,20 +74,20 @@ public abstract class OmfRecord { public byte getRecordType() { return recordType; } - + public int getRecordLength() { return recordLength; } - + public void readRecordHeader(BinaryReader reader) throws IOException { 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(); @@ -67,28 +96,28 @@ public abstract class OmfRecord { res += reader.readNextByte(); return res; } - + public boolean validCheckSum(BinaryReader reader) throws IOException { if (checkSum == 0) return true; // Sum compilers just set this to zero return (calcCheckSum(reader) == 0); } - + public boolean hasBigFields() { return ((recordType & 1)!=0); } - + public static int readInt1Or2(BinaryReader reader,boolean isBig) throws IOException { if (isBig) return (reader.readNextShort() & 0xffff); return (reader.readNextByte() & 0xff); } - + public static 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(); @@ -98,11 +127,11 @@ public abstract class OmfRecord { 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 + type &= 0xfe; // Mask off the least significant bit => 16/32 bit flag switch(type) { case THEADR: case LHEADR: @@ -120,9 +149,6 @@ public abstract class OmfRecord { case PUBDEF: res = new OmfSymbolRecord(reader,false); break; - case LINNUM: - res = new OmfLineNumberRecord(reader); - break; case LNAMES: res = new OmfNamesRecord(reader); break; @@ -153,12 +179,43 @@ public abstract class OmfRecord { case LCOMDEF: res = new OmfComdefRecord(reader,true); break; + 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: + res = new OmfUnsupportedRecord(reader, false); + break; + case LOCSYM: + case TYPDEF: + case CEXTDEF: + case COMDAT: + case LINSYM: + case ALIAS: + case BAKPAT: + case NBKPAT: + case LLNAMES: + case VERNUM: + case VENDEXT: + res = new OmfUnsupportedRecord(reader, true); + break; default: throw new OmfException("Unrecognized record type"); } return res; } - + /** * Read the OMF string format, 1-byte length, followed by that many ascii characters * @param reader diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfUnsupportedRecord.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfUnsupportedRecord.java new file mode 100644 index 0000000000..74c0c52d7a --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfUnsupportedRecord.java @@ -0,0 +1,52 @@ +/* ### + * IP: GHIDRA + * REVIEWED: NO + * + * 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 { + private long offset; + private boolean logMessage; + + /*** + * Skip an unsupported OMF record. + * + * @param reader The byte stream with the unsupported record to skip + * @throws IOException + */ + public OmfUnsupportedRecord(BinaryReader reader, boolean log) throws IOException { + readRecordHeader(reader); + offset = reader.getPointerIndex(); + logMessage = log; + + reader.setPointerIndex(reader.getPointerIndex() + getRecordLength()); + } + + public boolean doLogMessage() { + return logMessage; + } + + /*** + * Get a message suitable for logging about this record + * @return String Message text about record + */ + public String getMessage() { + return "Unsupported OMF record of type " + Long.toHexString((getRecordType() & 0xff)) + " of length " + getRecordLength() + " at " + offset; + } + +} \ No newline at end of file diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/OmfLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/OmfLoader.java index 4a1ced92b0..32341f1c86 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/OmfLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/OmfLoader.java @@ -115,7 +115,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()); From 5105aa815705d96d2e043107cc042000fd12c3e1 Mon Sep 17 00:00:00 2001 From: Ryan Kurtz Date: Tue, 10 Jan 2023 09:34:47 -0500 Subject: [PATCH 2/2] GP-2997: OmfLoader refactor, cleanup, code formatting --- .../util/bin/format/omf/OmfComdefRecord.java | 18 +- .../util/bin/format/omf/OmfCommentRecord.java | 10 +- .../bin/format/omf/OmfEnumeratedData.java | 8 +- .../bin/format/omf/OmfExternalSymbol.java | 20 +- .../util/bin/format/omf/OmfFileHeader.java | 210 +++++++----- .../util/bin/format/omf/OmfFixupRecord.java | 217 +++++++------ .../util/bin/format/omf/OmfGroupRecord.java | 37 +-- .../util/bin/format/omf/OmfIteratedData.java | 16 +- .../util/bin/format/omf/OmfLibraryRecord.java | 59 ++-- .../app/util/bin/format/omf/OmfModuleEnd.java | 16 +- .../util/bin/format/omf/OmfNamesRecord.java | 9 +- .../bin/format/omf/OmfObsoleteRecord.java | 34 ++ .../app/util/bin/format/omf/OmfRecord.java | 306 ++++++++++-------- .../util/bin/format/omf/OmfSegmentHeader.java | 120 +++---- .../app/util/bin/format/omf/OmfSymbol.java | 23 +- .../util/bin/format/omf/OmfSymbolRecord.java | 22 +- .../util/bin/format/omf/OmfUnknownRecord.java | 34 ++ .../bin/format/omf/OmfUnsupportedRecord.java | 32 +- .../ghidra/app/util/opinion/OmfLoader.java | 2 - 19 files changed, 663 insertions(+), 530 deletions(-) create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfObsoleteRecord.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfUnknownRecord.java diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfComdefRecord.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfComdefRecord.java index e65ca6edb8..4f681d3189 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfComdefRecord.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfComdefRecord.java @@ -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 symbollist = new ArrayList(); - 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; } - + } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfCommentRecord.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfCommentRecord.java index 4a3b21807f..2f56174264 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfCommentRecord.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfCommentRecord.java @@ -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; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfEnumeratedData.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfEnumeratedData.java index da885b6481..0f51568299 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfEnumeratedData.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfEnumeratedData.java @@ -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(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfExternalSymbol.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfExternalSymbol.java index 65cfb8c266..b7b61db970 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfExternalSymbol.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfExternalSymbol.java @@ -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 symbollist = new ArrayList(); - - 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; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfFileHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfFileHeader.java index 53c4a22e9e..9b8aae7bda 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfFileHeader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfFileHeader.java @@ -15,9 +15,8 @@ */ 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; @@ -27,8 +26,8 @@ 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 nameList = new ArrayList(); // Indexable List of segment, group, ... names private ArrayList segments = new ArrayList(); @@ -132,11 +131,11 @@ public class OmfFileHeader extends OmfRecord { */ public void sortSegmentDataBlocks() { if (extraSeg != null) { - for(int i=0;isegments.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); @@ -180,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; } @@ -202,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(); } - 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; } @@ -239,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); } @@ -257,53 +256,24 @@ 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 instanceof OmfFileHeader)) { throw new OmfException("Object file does not start with proper header"); } - OmfFileHeader header = (OmfFileHeader)record; - while(!(record instanceof OmfModuleEnd)) { - if (monitor.isCancelled()) { - break; // Return what we have - } + OmfFileHeader header = (OmfFileHeader) record; + + while (true) { record = OmfRecord.readRecord(reader); - if(record instanceof OmfCommentRecord coment) { - byte commentClass = coment.getCommentClass(); - if (commentClass == OmfCommentRecord.COMMENT_CLASS_TRANSLATOR) { - header.translator = coment.getValue(); - } - else if (commentClass == OmfCommentRecord.COMMENT_CLASS_LIBMOD) { - header.libModuleName = coment.getValue(); - } - } else if(initialCommentsOnly) { + + if (monitor.isCancelled()) { break; } - } - return header; - } - - /** - * Parse the entire object file - * @param reader is the byte stream - * @param monitor is checked for cancel button - * @return the header record as root of object - * @throws IOException for problems reading data - * @throws OmfException for malformed records - */ - public static OmfFileHeader parse(BinaryReader reader,TaskMonitor monitor, MessageLog log) throws IOException, OmfException { - OmfRecord record = OmfRecord.readRecord(reader); - if (!(record instanceof OmfFileHeader)) { - throw new OmfException("Object file does not start with proper header"); - } - OmfFileHeader header = (OmfFileHeader)record; - Object lastDataBlock = null; - - while(!(record instanceof OmfModuleEnd)) { - if (monitor.isCancelled()) { - break; // Return what we have + if (record instanceof OmfModuleEnd) { + break; } - record = OmfRecord.readRecord(reader); + if (record instanceof OmfCommentRecord comment) { byte commentClass = comment.getCommentClass(); if (commentClass == OmfCommentRecord.COMMENT_CLASS_TRANSLATOR) { @@ -312,38 +282,96 @@ public class OmfFileHeader extends OmfRecord { else if (commentClass == OmfCommentRecord.COMMENT_CLASS_LIBMOD) { header.libModuleName = comment.getValue(); } - } else if(record instanceof OmfModuleEnd) { - // We are not currently examining the end module record - // header.endModule = end; - } else if(record instanceof OmfComdefRecord comdef) { + } + else if (initialCommentsOnly) { + break; + } + } + 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, MessageLog log) + throws IOException, OmfException { + OmfRecord record = OmfRecord.readRecord(reader); + if (!(record instanceof OmfFileHeader)) { + throw new OmfException("Object file does not start with proper header"); + } + OmfFileHeader header = (OmfFileHeader) record; + Object lastDataBlock = null; + + while (true) { + record = OmfRecord.readRecord(reader); + + 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 = comment.getValue(); + } + else if (commentClass == OmfCommentRecord.COMMENT_CLASS_LIBMOD) { + header.libModuleName = comment.getValue(); + } + } + else if (record instanceof OmfComdefRecord comdef) { header.evaluateComdef(comdef); - header.externsymbols.add((OmfExternalSymbol)record); - } else if(record instanceof OmfExternalSymbol external) { + header.externsymbols.add((OmfExternalSymbol) record); + } + else if (record instanceof OmfExternalSymbol external) { header.externsymbols.add(external); - } else if(record instanceof OmfSymbolRecord symbol) { + } + else if (record instanceof OmfSymbolRecord symbol) { header.symbols.add(symbol); - } else if(record instanceof OmfNamesRecord names) { + } + else if (record instanceof OmfNamesRecord names) { names.appendNames(header.nameList); // Keep names, otherwise don't save record - } else if(record instanceof OmfSegmentHeader seghead) { + } + else if (record instanceof OmfSegmentHeader seghead) { header.segments.add(seghead); - } else if(record instanceof OmfGroupRecord group) { + } + else if (record instanceof OmfGroupRecord group) { header.groups.add(group); - } else if(record instanceof OmfFixupRecord fixuprec) { + } + else if (record instanceof OmfFixupRecord fixuprec) { fixuprec.setDataBlock(lastDataBlock); header.fixup.add(fixuprec); - } else if(record instanceof OmfEnumeratedData enumheader) { + } + else if (record instanceof OmfEnumeratedData enumheader) { header.addEnumeratedBlock(enumheader); lastDataBlock = enumheader; - } else if(record instanceof OmfIteratedData iterheader) { - 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; - } else if(record instanceof OmfUnsupportedRecord unsupported) { - if(unsupported.doLogMessage()) - log.appendMsg(unsupported.getMessage()); + } + 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; @@ -357,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 segments,ArrayList groups) throws OmfException { + public static void doLinking(long startAddress, ArrayList segments, + ArrayList groups) throws OmfException { // Link anything in groups first for (int i = 0; i < groups.size(); ++i) { OmfGroupRecord group = groups.get(i); @@ -367,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 subreclist = new ArrayList(); - 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 externsyms,Language lang) { - for(int i=0;i<4;++i) { + + public FixupState(OmfFileHeader header, ArrayList 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; - } + } } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfGroupRecord.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfGroupRecord.java index 5d2957158e..2b512ea83c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfGroupRecord.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfGroupRecord.java @@ -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 grouplist = new ArrayList(); - 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 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(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfIteratedData.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfIteratedData.java index 9a26034fb2..99c7fb6919 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfIteratedData.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfIteratedData.java @@ -34,7 +34,7 @@ public class OmfIteratedData extends OmfRecord implements OmfData { segmentIndex = OmfRecord.readIndex(reader); dataOffset = OmfRecord.readInt2Or4(reader, hasBigFields); ArrayList blocklist = new ArrayList(); - 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 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(); + res.members = new ArrayList(); 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(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfModuleEnd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfModuleEnd.java index 7267f67b12..a5def4055f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfModuleEnd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfModuleEnd.java @@ -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); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfNamesRecord.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfNamesRecord.java index 7246540ffc..9333618bbd 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfNamesRecord.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfNamesRecord.java @@ -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 name; - + public OmfNamesRecord(BinaryReader reader) throws IOException { readRecordHeader(reader); - long max = reader.getPointerIndex() + getRecordLength() -1; + long max = reader.getPointerIndex() + getRecordLength() - 1; name = new ArrayList(); - while(reader.getPointerIndex() < max) { + while (reader.getPointerIndex() < max) { String nm = OmfRecord.readString(reader); name.add(nm); } readCheckSumByte(reader); } - + public void appendNames(ArrayList namelist) { namelist.addAll(name); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfObsoleteRecord.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfObsoleteRecord.java new file mode 100644 index 0000000000..9d14962827 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfObsoleteRecord.java @@ -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()); + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfRecord.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfRecord.java index c10dddec51..2604fc88c1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfRecord.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfRecord.java @@ -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,58 +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 RHEADR = (byte)0x6E; // Obselete - public final static byte REGINT = (byte)0x70; // Obselete - public final static byte REDATA = (byte)0x72; // Obselete - public final static byte RIDATA = (byte)0x74; // Obselete - public final static byte OVLDEF = (byte)0x76; // Obselete - public final static byte ENDREC = (byte)0x78; // Obselete - public final static byte BLKDEF = (byte)0x7A; // Obselete - public final static byte BLKEND = (byte)0x7C; // Obselete - public final static byte DEBSYM = (byte)0x7E; // Obselete - public final static byte THEADR = (byte)0x80; - public final static byte LHEADR = (byte)0x82; - public final static byte PEDATA = (byte)0x84; // Obselete - public final static byte PIDATA = (byte)0x86; // Obselete - 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; // Obselete - public final static byte PUBDEF = (byte)0x90; - public final static byte LOCSYM = (byte)0x92; // Obselete - 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; // Obselete - public final static byte LIBNAM = (byte)0xA6; // Obselete - public final static byte LIBLOC = (byte)0xA8; // Obselete - public final static byte LIBDIC = (byte)0xAA; // Obselete - 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; + 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() { @@ -79,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; } @@ -92,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 16/32 bit flag - 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 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; - 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: - res = new OmfUnsupportedRecord(reader, false); - break; - case LOCSYM: - case TYPDEF: - case CEXTDEF: - case COMDAT: - case LINSYM: - case ALIAS: - case BAKPAT: - case NBKPAT: - case LLNAMES: - case VERNUM: - case VENDEXT: - res = new OmfUnsupportedRecord(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 ""; + } + + @Override + public String toString() { + return String.format("name: %s, type: 0x%x, offset: 0x%x, length: 0x%x", + getRecordName(recordType), recordType, recordOffset, recordLength); + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfSegmentHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfSegmentHeader.java index 78b503cf63..5dfcc66af6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfSegmentHeader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfSegmentHeader.java @@ -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 dataBlocks = new ArrayList(); - 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 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 symbollist = new ArrayList(); - 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]; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfUnknownRecord.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfUnknownRecord.java new file mode 100644 index 0000000000..3976e6d953 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfUnknownRecord.java @@ -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()); + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfUnsupportedRecord.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfUnsupportedRecord.java index 74c0c52d7a..b2dfd2a899 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfUnsupportedRecord.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/omf/OmfUnsupportedRecord.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: NO * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,36 +16,19 @@ package ghidra.app.util.bin.format.omf; import java.io.IOException; + import ghidra.app.util.bin.BinaryReader; public class OmfUnsupportedRecord extends OmfRecord { - private long offset; - private boolean logMessage; - /*** - * Skip an unsupported OMF record. + /** + * Create a new {@link OmfUnsupportedRecord} * - * @param reader The byte stream with the unsupported record to skip - * @throws IOException + * @param reader A {@link BinaryReader} positioned at the start of the record + * @throws IOException If an IO-related error occurred */ - public OmfUnsupportedRecord(BinaryReader reader, boolean log) throws IOException { + public OmfUnsupportedRecord(BinaryReader reader) throws IOException { readRecordHeader(reader); - offset = reader.getPointerIndex(); - logMessage = log; - reader.setPointerIndex(reader.getPointerIndex() + getRecordLength()); } - - public boolean doLogMessage() { - return logMessage; - } - - /*** - * Get a message suitable for logging about this record - * @return String Message text about record - */ - public String getMessage() { - return "Unsupported OMF record of type " + Long.toHexString((getRecordType() & 0xff)) + " of length " + getRecordLength() + " at " + offset; - } - -} \ No newline at end of file +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/OmfLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/OmfLoader.java index 32341f1c86..4b394c3015 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/OmfLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/OmfLoader.java @@ -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)"; @@ -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