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
@@ -4,9 +4,9 @@
* 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.
@@ -23,36 +23,11 @@ import ghidra.util.exception.DuplicateNameException;
/**
* 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 {
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;
}
public record Omf2or4(int length, long value) implements StructConverter {
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
@@ -35,7 +35,7 @@ public class OmfUtils {
public static final String CATEGORY_PATH = "/OMF";
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());
}
@@ -4,9 +4,9 @@
* 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.
@@ -19,7 +19,8 @@ import java.io.IOException;
import java.util.ArrayList;
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.util.exception.DuplicateNameException;
@@ -83,14 +84,17 @@ public class OmfIteratedData extends OmfData {
* Contain the definition of one part of a datablock with possible recursion
*/
public static class DataBlock {
private Omf2or4 repeatCount;
private int repeatCount;
private int blockCount;
private byte[] simpleBlock = null;
private DataBlock[] nestedBlock = null;
public static DataBlock read(BinaryReader reader, boolean hasBigFields) throws IOException {
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();
if (subblock.blockCount == 0) {
int size = reader.readNextByte() & 0xff;
@@ -115,7 +119,7 @@ public class OmfIteratedData extends OmfData {
* @return The position after the block
*/
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) {
for (byte element : simpleBlock) {
buffer[pos] = element;
@@ -144,7 +148,7 @@ public class OmfIteratedData extends OmfData {
length += block.getLength();
}
}
return length * (int) repeatCount.value();
return length * repeatCount;
}
/**
@@ -15,14 +15,14 @@
*/
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.util.ArrayList;
import java.util.List;
import ghidra.app.util.bin.*;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**
* See Apple's -- PEFBinaryFormat.h
* <pre>
@@ -103,6 +103,10 @@ public class ContainerHeader implements StructConverter {
}
_sections.add(section);
}
if (_loader == null) {
throw new PefException("Loader section not found!");
}
}
/**
@@ -4,9 +4,9 @@
* 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.
@@ -113,8 +113,9 @@ public class SectionHeader implements StructConverter {
* @param monitor the task monitor
* @return the unpacked data
* @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) {
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();
if (value == -1) {
throw new IllegalStateException();
throw new IllegalStateException("Unexpectedly reached end-of-file");
}
int count = value & 0x1f;//count is the lower 5 bits...
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;
while (true) {
unpacked <<= 7;
int value = input.read();
if (value == -1) {
throw new IllegalStateException("Unexpectedly reached end-of-file");
}
unpacked += (value & 0x7f);
if ((value & 0x80) == 0x00) {
break;
@@ -35,6 +35,14 @@ import ghidra.program.model.symbol.*;
import ghidra.util.exception.CancelledException;
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 final static String PEF_NAME = "Preferred Executable Format (PEF)";