Merge branch 'GP-7071_ryanmkurtz_pef-omf' into patch

This commit is contained in:
Ryan Kurtz
2026-07-17 11:18:54 -04:00
6 changed files with 43 additions and 48 deletions

View File

@@ -23,36 +23,11 @@ import ghidra.util.exception.DuplicateNameException;
/** /**
* An OMF value that is either 2 or 4 bytes * An OMF value that is either 2 or 4 bytes
*
* @param length 2 or 4
* @param value The 2 or 4 byte value
*/ */
public class Omf2or4 implements StructConverter { public record Omf2or4(int length, long value) implements StructConverter {
private int length;
private long value;
/**
* Creates a new {@link Omf2or4}
*
* @param length 2 or 4
* @param value The 2 or 4 byte value
*/
public Omf2or4(int length, long value) {
this.length = length;
this.value = value;
}
/**
* {@return the length of the value (2 or 4)}
*/
public int length() {
return length;
}
/**
* {@return the value}
*/
public long value() {
return value;
}
@Override @Override
public DataType toDataType() throws DuplicateNameException, IOException { public DataType toDataType() throws DuplicateNameException, IOException {

View File

@@ -35,7 +35,7 @@ public class OmfUtils {
public static final String CATEGORY_PATH = "/OMF"; public static final String CATEGORY_PATH = "/OMF";
public static Omf2or4 readInt2Or4(BinaryReader reader, boolean isBig) throws IOException { public static Omf2or4 readInt2Or4(BinaryReader reader, boolean isBig) throws IOException {
return isBig ? new Omf2or4(4, reader.readNextInt()) return isBig ? new Omf2or4(4, reader.readNextUnsignedInt())
: new Omf2or4(2, reader.readNextUnsignedShort()); : new Omf2or4(2, reader.readNextUnsignedShort());
} }

View File

@@ -19,7 +19,8 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.omf.*; import ghidra.app.util.bin.format.omf.OmfException;
import ghidra.app.util.bin.format.omf.OmfUtils;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
@@ -83,14 +84,17 @@ public class OmfIteratedData extends OmfData {
* Contain the definition of one part of a datablock with possible recursion * Contain the definition of one part of a datablock with possible recursion
*/ */
public static class DataBlock { public static class DataBlock {
private Omf2or4 repeatCount; private int repeatCount;
private int blockCount; private int blockCount;
private byte[] simpleBlock = null; private byte[] simpleBlock = null;
private DataBlock[] nestedBlock = null; private DataBlock[] nestedBlock = null;
public static DataBlock read(BinaryReader reader, boolean hasBigFields) throws IOException { public static DataBlock read(BinaryReader reader, boolean hasBigFields) throws IOException {
DataBlock subblock = new DataBlock(); DataBlock subblock = new DataBlock();
subblock.repeatCount = OmfUtils.readInt2Or4(reader, hasBigFields); subblock.repeatCount = (int) OmfUtils.readInt2Or4(reader, hasBigFields).value();
if (subblock.repeatCount < 0) {
throw new IOException("Iterated block has negative repeat count");
}
subblock.blockCount = reader.readNextUnsignedShort(); subblock.blockCount = reader.readNextUnsignedShort();
if (subblock.blockCount == 0) { if (subblock.blockCount == 0) {
int size = reader.readNextByte() & 0xff; int size = reader.readNextByte() & 0xff;
@@ -115,7 +119,7 @@ public class OmfIteratedData extends OmfData {
* @return The position after the block * @return The position after the block
*/ */
public int fillBuffer(byte[] buffer, int pos) { public int fillBuffer(byte[] buffer, int pos) {
for (int i = 0; i < (int) repeatCount.value(); ++i) { for (int i = 0; i < repeatCount; ++i) {
if (simpleBlock != null) { if (simpleBlock != null) {
for (byte element : simpleBlock) { for (byte element : simpleBlock) {
buffer[pos] = element; buffer[pos] = element;
@@ -144,7 +148,7 @@ public class OmfIteratedData extends OmfData {
length += block.getLength(); length += block.getLength();
} }
} }
return length * (int) repeatCount.value(); return length * repeatCount;
} }
/** /**

View File

@@ -15,14 +15,14 @@
*/ */
package ghidra.app.util.bin.format.pef; package ghidra.app.util.bin.format.pef;
import ghidra.app.util.bin.*;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import ghidra.app.util.bin.*;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/** /**
* See Apple's -- PEFBinaryFormat.h * See Apple's -- PEFBinaryFormat.h
* <pre> * <pre>
@@ -103,6 +103,10 @@ public class ContainerHeader implements StructConverter {
} }
_sections.add(section); _sections.add(section);
} }
if (_loader == null) {
throw new PefException("Loader section not found!");
}
} }
/** /**

View File

@@ -113,8 +113,9 @@ public class SectionHeader implements StructConverter {
* @param monitor the task monitor * @param monitor the task monitor
* @return the unpacked data * @return the unpacked data
* @throws IOException if an i/o error occurs or the section is not packed. * @throws IOException if an i/o error occurs or the section is not packed.
* @throws IllegalStateException an an unexpected state occurs
*/ */
public byte[] getUnpackedData(TaskMonitor monitor) throws IOException { public byte[] getUnpackedData(TaskMonitor monitor) throws IOException, IllegalStateException {
if (getSectionKind() != SectionKind.PackedData) { if (getSectionKind() != SectionKind.PackedData) {
throw new IOException("Attempt to unpack a section that is not packed."); throw new IOException("Attempt to unpack a section that is not packed.");
} }
@@ -127,7 +128,7 @@ public class SectionHeader implements StructConverter {
} }
int value = input.read(); int value = input.read();
if (value == -1) { if (value == -1) {
throw new IllegalStateException(); throw new IllegalStateException("Unexpectedly reached end-of-file");
} }
int count = value & 0x1f;//count is the lower 5 bits... int count = value & 0x1f;//count is the lower 5 bits...
if (count == 0) { if (count == 0) {
@@ -218,11 +219,14 @@ public class SectionHeader implements StructConverter {
} }
} }
private int unpackNextValue(InputStream input) throws IOException { private int unpackNextValue(InputStream input) throws IOException, IllegalStateException {
int unpacked = 0; int unpacked = 0;
while (true) { while (true) {
unpacked <<= 7; unpacked <<= 7;
int value = input.read(); int value = input.read();
if (value == -1) {
throw new IllegalStateException("Unexpectedly reached end-of-file");
}
unpacked += (value & 0x7f); unpacked += (value & 0x7f);
if ((value & 0x80) == 0x00) { if ((value & 0x80) == 0x00) {
break; break;

View File

@@ -35,6 +35,14 @@ import ghidra.program.model.symbol.*;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
/**
* A {@link Loader} for Preferred Executable Format (PEF) files.
* <p>
* PEF was developed by Apple for use in its classic Mac OS operating system. BeOS on PowerPC
* systems also uses PEF.
*
* @see <a href="https://web.archive.org/web/20011017102300/http://developer.apple.com/techpubs/mac/runtimehtml/RTArch-89.html">PEF Structure</a>
*/
public class PefLoader extends AbstractProgramWrapperLoader { public class PefLoader extends AbstractProgramWrapperLoader {
public final static String PEF_NAME = "Preferred Executable Format (PEF)"; public final static String PEF_NAME = "Preferred Executable Format (PEF)";