Merge remote-tracking branch 'origin/Ghidra_12.1'

This commit is contained in:
Ryan Kurtz
2026-04-07 13:31:39 -04:00
6 changed files with 116 additions and 89 deletions
@@ -486,12 +486,7 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin
} }
protected void forgetAllBreakpoints(RemoveCollector r) { protected void forgetAllBreakpoints(RemoveCollector r) {
Collection<TraceBreakpointLocation> toForget = new ArrayList<>(); for (TraceBreakpointLocation tb : List.copyOf(logicalByBreakpoint.keySet())) {
for (AddressRange range : trace.getBaseAddressFactory().getAddressSet()) {
toForget.addAll(
trace.getBreakpointManager().getBreakpointsIntersecting(Lifespan.ALL, range));
}
for (TraceBreakpointLocation tb : toForget) {
forgetTraceBreakpoint(r, tb); forgetTraceBreakpoint(r, tb);
} }
} }
@@ -90,7 +90,7 @@ public class ExceptionDataDirectory extends DataDirectory {
} }
createDirectoryBookmark(program, addr); createDirectoryBookmark(program, addr);
if (functionEntries != null) { if (functionEntries != null) {
functionEntries.markup(program, addr); functionEntries.markup(program, addr, log);
} }
} }
} }
@@ -17,6 +17,7 @@ package ghidra.app.util.bin.format.pe;
import java.io.IOException; import java.io.IOException;
import ghidra.app.util.importer.MessageLog;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.program.model.util.CodeUnitInsertionException; import ghidra.program.model.util.CodeUnitInsertionException;
@@ -33,10 +34,11 @@ public interface ImageRuntimeFunctionEntries {
* *
* @param program The {@link Program} * @param program The {@link Program}
* @param start The start {@link Address} * @param start The start {@link Address}
* @param log The log
* @throws IOException If there was an IO-related error creating the data * @throws IOException If there was an IO-related error creating the data
* @throws DuplicateNameException If a data type of the same name already exists * @throws DuplicateNameException If a data type of the same name already exists
* @throws CodeUnitInsertionException If data creation failed * @throws CodeUnitInsertionException If data creation failed
*/ */
public void markup(Program program, Address start) throws CodeUnitInsertionException, public void markup(Program program, Address start, MessageLog log)
IOException, DuplicateNameException; throws CodeUnitInsertionException, IOException, DuplicateNameException;
} }
@@ -21,6 +21,7 @@ import java.util.List;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter; import ghidra.app.util.bin.StructConverter;
import ghidra.app.util.importer.MessageLog;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
@@ -65,49 +66,33 @@ public class ImageRuntimeFunctionEntries_ARM implements ImageRuntimeFunctionEntr
*/ */
ImageRuntimeFunctionEntries_ARM(BinaryReader reader, int size, NTHeader ntHeader) ImageRuntimeFunctionEntries_ARM(BinaryReader reader, int size, NTHeader ntHeader)
throws IOException { throws IOException {
int numEntries = size / ENTRY_SIZE; for (int i = 0; i < size / ENTRY_SIZE; i++) {
for (int i = 0; i < numEntries; i++) {
long beginAddress = reader.readNextUnsignedInt() & ~0x1L; // low bit is set when thumb long beginAddress = reader.readNextUnsignedInt() & ~0x1L; // low bit is set when thumb
int data = reader.readNextInt(); int data = reader.readNextInt();
if (beginAddress == 0 && data == 0) {
break;
}
functionEntries.add(new ImageRuntimeFunctionEntry_ARM(beginAddress, data)); functionEntries.add(new ImageRuntimeFunctionEntry_ARM(beginAddress, data));
} }
} }
@Override @Override
public void markup(Program program, Address headerStart) throws CodeUnitInsertionException, public void markup(Program program, Address headerStart, MessageLog log)
IOException, DuplicateNameException { throws CodeUnitInsertionException, IOException, DuplicateNameException {
StructureDataType exceptionInfoStruct = new StructureDataType("_IMAGE_RUNTIME_FUNCTION_ENTRY", 0);
exceptionInfoStruct.setPackingEnabled(true);
exceptionInfoStruct.add(StructConverter.IBO32, "BeginAddress", null);
exceptionInfoStruct.add(StructConverter.IBO32, "ExceptionInfo", null);
StructureDataType unwindDataStruct = new StructureDataType("_IMAGE_RUNTIME_FUNCTION_ENTRY_2", 0);
unwindDataStruct.setPackingEnabled(true);
unwindDataStruct.add(StructConverter.IBO32, "BeginAddress", null);
try {
unwindDataStruct.addBitField(StructConverter.DWORD, 2, "Flag", null);
unwindDataStruct.addBitField(StructConverter.DWORD, 11, "FunctionLength", null);
unwindDataStruct.addBitField(StructConverter.DWORD, 2, "Ret", null);
unwindDataStruct.addBitField(StructConverter.DWORD, 1, "H", null);
unwindDataStruct.addBitField(StructConverter.DWORD, 3, "Reg", null);
unwindDataStruct.addBitField(StructConverter.DWORD, 1, "R", null);
unwindDataStruct.addBitField(StructConverter.DWORD, 1, "L", null);
unwindDataStruct.addBitField(StructConverter.DWORD, 1, "C", null);
unwindDataStruct.addBitField(StructConverter.DWORD, 10, "StackAdjust", null);
}
catch (InvalidDataTypeException e) {
throw new IOException(e);
}
Address addr = headerStart; Address addr = headerStart;
DataType exceptionInfoDt = null;
DataType packedUnwindDt = null;
for (ImageRuntimeFunctionEntry_ARM entry : functionEntries) { for (ImageRuntimeFunctionEntry_ARM entry : functionEntries) {
DataType struct = entry.isExceptionInfoRVA() ? exceptionInfoStruct : unwindDataStruct; if (entry.isExceptionInfoRVA()) {
DataUtilities.createData(program, addr, struct, struct.getLength(), true, if (exceptionInfoDt == null) {
DataUtilities.ClearDataMode.CHECK_FOR_SPACE); exceptionInfoDt = entry.toDataType();
}
PeUtils.createData(program, addr, exceptionInfoDt, log);
}
else {
if (packedUnwindDt == null) {
packedUnwindDt = entry.toDataType();
}
PeUtils.createData(program, addr, packedUnwindDt, log);
}
entry.markup(program, log);
addr = addr.add(ENTRY_SIZE); addr = addr.add(ENTRY_SIZE);
} }
} }
@@ -118,12 +103,10 @@ public class ImageRuntimeFunctionEntries_ARM implements ImageRuntimeFunctionEntr
* @param beginAddress The RVA of the corresponding function * @param beginAddress The RVA of the corresponding function
* @param data The exception info RVA or the packed unwind data, depending on lower 2 bit flag * @param data The exception info RVA or the packed unwind data, depending on lower 2 bit flag
*/ */
record ImageRuntimeFunctionEntry_ARM(long beginAddress, int data) { record ImageRuntimeFunctionEntry_ARM(long beginAddress, int data) implements StructConverter {
/** /**
* Checks whether or not this entry is an exception info RVA or packed unwind data * {@return whether or not this entry is an exception info RVA or packed unwind data}
*
* @return True if this entry is an exception info RVA, or false if it's packed unwind data
*/ */
public boolean isExceptionInfoRVA() { public boolean isExceptionInfoRVA() {
return (data & 0x3) == 0; return (data & 0x3) == 0;
@@ -133,15 +116,48 @@ public class ImageRuntimeFunctionEntries_ARM implements ImageRuntimeFunctionEntr
* Marks up this entry * Marks up this entry
* *
* @param program The {@link Program} * @param program The {@link Program}
* @param log The log
* @throws IOException If there was an IO-related error creating the data * @throws IOException If there was an IO-related error creating the data
* @throws DuplicateNameException If a data type of the same name already exists * @throws DuplicateNameException If a data type of the same name already exists
* @throws CodeUnitInsertionException If data creation failed * @throws CodeUnitInsertionException If data creation failed
*/ */
public void markup(Program program) public void markup(Program program, MessageLog log)
throws DuplicateNameException, IOException, CodeUnitInsertionException { throws DuplicateNameException, IOException, CodeUnitInsertionException {
if (isExceptionInfoRVA()) { if (isExceptionInfoRVA()) {
// TODO // TODO
} }
} }
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType struct;
if (isExceptionInfoRVA()) {
struct = new StructureDataType("_IMAGE_RUNTIME_FUNCTION_ENTRY", 0);
struct.setPackingEnabled(true);
struct.add(StructConverter.IBO32, "BeginAddress", null);
struct.add(StructConverter.IBO32, "ExceptionInfo", null);
}
else {
struct = new StructureDataType("_IMAGE_RUNTIME_FUNCTION_ENTRY_2", 0);
struct.setPackingEnabled(true);
struct.add(StructConverter.IBO32, "BeginAddress", null);
try {
struct.addBitField(StructConverter.DWORD, 2, "Flag", null);
struct.addBitField(StructConverter.DWORD, 11, "FunctionLength", null);
struct.addBitField(StructConverter.DWORD, 2, "Ret", null);
struct.addBitField(StructConverter.DWORD, 1, "H", null);
struct.addBitField(StructConverter.DWORD, 3, "Reg", null);
struct.addBitField(StructConverter.DWORD, 1, "R", null);
struct.addBitField(StructConverter.DWORD, 1, "L", null);
struct.addBitField(StructConverter.DWORD, 1, "C", null);
struct.addBitField(StructConverter.DWORD, 10, "StackAdjust", null);
}
catch (InvalidDataTypeException e) {
throw new IOException(e);
}
}
struct.setCategoryPath(new CategoryPath("/PE"));
return struct;
}
} }
} }
@@ -21,6 +21,7 @@ import java.util.List;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter; import ghidra.app.util.bin.StructConverter;
import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.opinion.AbstractProgramLoader; import ghidra.app.util.opinion.AbstractProgramLoader;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
@@ -85,42 +86,34 @@ public class ImageRuntimeFunctionEntries_X86 implements ImageRuntimeFunctionEntr
*/ */
ImageRuntimeFunctionEntries_X86(BinaryReader reader, int size, NTHeader ntHeader) ImageRuntimeFunctionEntries_X86(BinaryReader reader, int size, NTHeader ntHeader)
throws IOException { throws IOException {
for (int i = 0; i < size / ENTRY_SIZE; i++) {
int numEntries = size / ENTRY_SIZE;
for (int i = 0; i < numEntries; i++) {
long beginAddress = reader.readNextUnsignedInt(); long beginAddress = reader.readNextUnsignedInt();
long endAddress = reader.readNextUnsignedInt(); long endAddress = reader.readNextUnsignedInt();
long unwindInfoAddressOrData = reader.readNextUnsignedInt(); long unwindInfoAddressOrData = reader.readNextUnsignedInt();
PEx64UnwindInfo unwindInfo = null;
if (beginAddress == 0 && endAddress == 0 && unwindInfoAddressOrData == 0) { if (unwindInfoAddressOrData != 0) {
break; unwindInfo =
PEx64UnwindInfo.readUnwindInfo(reader, unwindInfoAddressOrData, ntHeader);
} }
PEx64UnwindInfo unwindInfo = functionEntries.add(new ImageRuntimeFunctionEntry_X86(beginAddress, endAddress,
PEx64UnwindInfo.readUnwindInfo(reader, unwindInfoAddressOrData, ntHeader); unwindInfoAddressOrData, unwindInfo));
ImageRuntimeFunctionEntry_X86 entry = new ImageRuntimeFunctionEntry_X86(beginAddress,
endAddress, unwindInfoAddressOrData, unwindInfo);
functionEntries.add(entry);
} }
} }
@Override @Override
public void markup(Program program, Address headerStart) throws CodeUnitInsertionException, public void markup(Program program, Address headerStart, MessageLog log)
IOException, DuplicateNameException { throws CodeUnitInsertionException, IOException, DuplicateNameException {
StructureDataType struct = new StructureDataType("_IMAGE_RUNTIME_FUNCTION_ENTRY", 0); Address addr = headerStart;
struct.add(StructConverter.IBO32, "BeginAddress", null); DataType dt = null;
struct.add(StructConverter.DWORD, "EndAddress",
"Apply ImageBaseOffset32 to see reference");
struct.add(StructConverter.IBO32, "UnwindInfoAddressOrData", null);
ArrayDataType arr = new ArrayDataType(struct, functionEntries.size(), struct.getLength());
DataUtilities.createData(program, headerStart, arr, arr.getLength(), true,
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
for (ImageRuntimeFunctionEntry_X86 entry : functionEntries) { for (ImageRuntimeFunctionEntry_X86 entry : functionEntries) {
entry.markup(program); if (dt == null) {
dt = entry.toDataType();
}
PeUtils.createData(program, addr, dt, log);
entry.markup(program, log);
addr = addr.add(ENTRY_SIZE);
} }
} }
@@ -133,34 +126,39 @@ public class ImageRuntimeFunctionEntries_X86 implements ImageRuntimeFunctionEntr
* @param unwindInfo The parsed {@link PEx64UnwindInfo unwind information} * @param unwindInfo The parsed {@link PEx64UnwindInfo unwind information}
*/ */
record ImageRuntimeFunctionEntry_X86(long beginAddress, long endAddress, record ImageRuntimeFunctionEntry_X86(long beginAddress, long endAddress,
long unwindInfoAddressOrData, PEx64UnwindInfo unwindInfo) { long unwindInfoAddressOrData, PEx64UnwindInfo unwindInfo) implements StructConverter {
/** /**
* Marks up this entry * Marks up this entry
* *
* @param program The {@link Program} * @param program The {@link Program}
* @param log The log
* @throws IOException If there was an IO-related error creating the data * @throws IOException If there was an IO-related error creating the data
* @throws DuplicateNameException If a data type of the same name already exists * @throws DuplicateNameException If a data type of the same name already exists
*/ */
public void markup(Program program) throws DuplicateNameException, IOException { public void markup(Program program, MessageLog log)
throws DuplicateNameException, IOException {
if (beginAddress != 0 && !unwindInfo.hasChainedUnwindInfo()) { if (beginAddress != 0 && !unwindInfo.hasChainedUnwindInfo()) {
AbstractProgramLoader.markAsFunction(program, null, AbstractProgramLoader.markAsFunction(program, null,
program.getImageBase().add(beginAddress)); program.getImageBase().add(beginAddress));
} }
if (unwindInfoAddressOrData > 0) { if (unwindInfo != null) {
DataType dt = unwindInfo.toDataType();
Address start = program.getImageBase().add(unwindInfoAddressOrData); Address start = program.getImageBase().add(unwindInfoAddressOrData);
PeUtils.createData(program, start, unwindInfo.toDataType(), log);
}
}
try { @Override
DataUtilities.createData(program, start, dt, dt.getLength(), true, public DataType toDataType() throws DuplicateNameException, IOException {
DataUtilities.ClearDataMode.CHECK_FOR_SPACE); StructureDataType struct = new StructureDataType("_IMAGE_RUNTIME_FUNCTION_ENTRY", 0);
} struct.add(StructConverter.IBO32, "BeginAddress", null);
catch (CodeUnitInsertionException e) { struct.add(StructConverter.DWORD, "EndAddress",
// expected...ignore "Apply ImageBaseOffset32 to see reference");
} struct.add(StructConverter.IBO32, "UnwindInfoAddressOrData", null);
} struct.setCategoryPath(new CategoryPath("/PE"));
return struct;
} }
} }
} }
@@ -110,6 +110,22 @@ public class PEx64UnwindInfoDataType extends DynamicDataType {
if (hasUnwindHandler(flags)) { if (hasUnwindHandler(flags)) {
struct.add(new ArrayDataType(UnsignedLongDataType.dataType, 0, -1), struct.add(new ArrayDataType(UnsignedLongDataType.dataType, 0, -1),
"ExceptionData", null); "ExceptionData", null);
// TODO: somehow check for __C_specific_handler and markup:
/*-----------------------------------------------------------------------------
// C Scope table entry
typedef struct _C_SCOPE_TABLE_ENTRY {
ULONG Begin; // +0x00 - Begin of guarded code block
ULONG End; // +0x04 - End of target code block
ULONG Handler; // +0x08 - Exception filter function (or “__finally” handler)
ULONG Target; // +0x0C - Exception handler pointer (the code inside __except block)
} C_SCOPE_TABLE_ENTRY, *PC_SCOPE_TABLE_ENTRY;
// C Scope table
typedef struct _C_SCOPE_TABLE {
ULONG NumEntries; // +0x00 - Number of entries
C_SCOPE_TABLE_ENTRY Table[1]; // +0x04 - Scope table array
} C_SCOPE_TABLE, *PC_SCOPE_TABLE;
----------------------------------------------------------------------------*/
} }
} }
else if (hasChainedUnwindInfo(flags)) { else if (hasChainedUnwindInfo(flags)) {