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) {
Collection<TraceBreakpointLocation> toForget = new ArrayList<>();
for (AddressRange range : trace.getBaseAddressFactory().getAddressSet()) {
toForget.addAll(
trace.getBreakpointManager().getBreakpointsIntersecting(Lifespan.ALL, range));
}
for (TraceBreakpointLocation tb : toForget) {
for (TraceBreakpointLocation tb : List.copyOf(logicalByBreakpoint.keySet())) {
forgetTraceBreakpoint(r, tb);
}
}
@@ -90,7 +90,7 @@ public class ExceptionDataDirectory extends DataDirectory {
}
createDirectoryBookmark(program, addr);
if (functionEntries != null) {
functionEntries.markup(program, addr);
functionEntries.markup(program, addr, log);
}
}
}
@@ -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.
@@ -17,6 +17,7 @@ package ghidra.app.util.bin.format.pe;
import java.io.IOException;
import ghidra.app.util.importer.MessageLog;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.program.model.util.CodeUnitInsertionException;
@@ -33,10 +34,11 @@ public interface ImageRuntimeFunctionEntries {
*
* @param program The {@link Program}
* @param start The start {@link Address}
* @param log The log
* @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 CodeUnitInsertionException If data creation failed
*/
public void markup(Program program, Address start) throws CodeUnitInsertionException,
IOException, DuplicateNameException;
public void markup(Program program, Address start, MessageLog log)
throws CodeUnitInsertionException, IOException, DuplicateNameException;
}
@@ -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.
@@ -21,6 +21,7 @@ import java.util.List;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.app.util.importer.MessageLog;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.Program;
@@ -65,49 +66,33 @@ public class ImageRuntimeFunctionEntries_ARM implements ImageRuntimeFunctionEntr
*/
ImageRuntimeFunctionEntries_ARM(BinaryReader reader, int size, NTHeader ntHeader)
throws IOException {
int numEntries = size / ENTRY_SIZE;
for (int i = 0; i < numEntries; i++) {
for (int i = 0; i < size / ENTRY_SIZE; i++) {
long beginAddress = reader.readNextUnsignedInt() & ~0x1L; // low bit is set when thumb
int data = reader.readNextInt();
if (beginAddress == 0 && data == 0) {
break;
}
functionEntries.add(new ImageRuntimeFunctionEntry_ARM(beginAddress, data));
}
}
@Override
public void markup(Program program, Address headerStart) 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);
}
public void markup(Program program, Address headerStart, MessageLog log)
throws CodeUnitInsertionException, IOException, DuplicateNameException {
Address addr = headerStart;
DataType exceptionInfoDt = null;
DataType packedUnwindDt = null;
for (ImageRuntimeFunctionEntry_ARM entry : functionEntries) {
DataType struct = entry.isExceptionInfoRVA() ? exceptionInfoStruct : unwindDataStruct;
DataUtilities.createData(program, addr, struct, struct.getLength(), true,
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
if (entry.isExceptionInfoRVA()) {
if (exceptionInfoDt == null) {
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);
}
}
@@ -118,12 +103,10 @@ public class ImageRuntimeFunctionEntries_ARM implements ImageRuntimeFunctionEntr
* @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
*/
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 True if this entry is an exception info RVA, or false if it's packed unwind data
* {@return whether or not this entry is an exception info RVA or packed unwind data}
*/
public boolean isExceptionInfoRVA() {
return (data & 0x3) == 0;
@@ -133,15 +116,48 @@ public class ImageRuntimeFunctionEntries_ARM implements ImageRuntimeFunctionEntr
* Marks up this entry
*
* @param program The {@link Program}
* @param log The log
* @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 CodeUnitInsertionException If data creation failed
*/
public void markup(Program program)
public void markup(Program program, MessageLog log)
throws DuplicateNameException, IOException, CodeUnitInsertionException {
if (isExceptionInfoRVA()) {
// 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.StructConverter;
import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.opinion.AbstractProgramLoader;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.*;
@@ -85,42 +86,34 @@ public class ImageRuntimeFunctionEntries_X86 implements ImageRuntimeFunctionEntr
*/
ImageRuntimeFunctionEntries_X86(BinaryReader reader, int size, NTHeader ntHeader)
throws IOException {
int numEntries = size / ENTRY_SIZE;
for (int i = 0; i < numEntries; i++) {
for (int i = 0; i < size / ENTRY_SIZE; i++) {
long beginAddress = reader.readNextUnsignedInt();
long endAddress = reader.readNextUnsignedInt();
long unwindInfoAddressOrData = reader.readNextUnsignedInt();
PEx64UnwindInfo unwindInfo = null;
if (beginAddress == 0 && endAddress == 0 && unwindInfoAddressOrData == 0) {
break;
if (unwindInfoAddressOrData != 0) {
unwindInfo =
PEx64UnwindInfo.readUnwindInfo(reader, unwindInfoAddressOrData, ntHeader);
}
PEx64UnwindInfo unwindInfo =
PEx64UnwindInfo.readUnwindInfo(reader, unwindInfoAddressOrData, ntHeader);
ImageRuntimeFunctionEntry_X86 entry = new ImageRuntimeFunctionEntry_X86(beginAddress,
endAddress, unwindInfoAddressOrData, unwindInfo);
functionEntries.add(entry);
functionEntries.add(new ImageRuntimeFunctionEntry_X86(beginAddress, endAddress,
unwindInfoAddressOrData, unwindInfo));
}
}
@Override
public void markup(Program program, Address headerStart) throws CodeUnitInsertionException,
IOException, DuplicateNameException {
StructureDataType struct = new StructureDataType("_IMAGE_RUNTIME_FUNCTION_ENTRY", 0);
struct.add(StructConverter.IBO32, "BeginAddress", 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);
public void markup(Program program, Address headerStart, MessageLog log)
throws CodeUnitInsertionException, IOException, DuplicateNameException {
Address addr = headerStart;
DataType dt = null;
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}
*/
record ImageRuntimeFunctionEntry_X86(long beginAddress, long endAddress,
long unwindInfoAddressOrData, PEx64UnwindInfo unwindInfo) {
long unwindInfoAddressOrData, PEx64UnwindInfo unwindInfo) implements StructConverter {
/**
* Marks up this entry
*
* @param program The {@link Program}
* @param log The log
* @throws IOException If there was an IO-related error creating the data
* @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()) {
AbstractProgramLoader.markAsFunction(program, null,
program.getImageBase().add(beginAddress));
}
if (unwindInfoAddressOrData > 0) {
DataType dt = unwindInfo.toDataType();
if (unwindInfo != null) {
Address start = program.getImageBase().add(unwindInfoAddressOrData);
try {
DataUtilities.createData(program, start, dt, dt.getLength(), true,
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
}
catch (CodeUnitInsertionException e) {
// expected...ignore
}
PeUtils.createData(program, start, unwindInfo.toDataType(), log);
}
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType struct = new StructureDataType("_IMAGE_RUNTIME_FUNCTION_ENTRY", 0);
struct.add(StructConverter.IBO32, "BeginAddress", null);
struct.add(StructConverter.DWORD, "EndAddress",
"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)) {
struct.add(new ArrayDataType(UnsignedLongDataType.dataType, 0, -1),
"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)) {