diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/DebuggerLogicalBreakpointServicePlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/DebuggerLogicalBreakpointServicePlugin.java index 39fc24af5f..295ac707b3 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/DebuggerLogicalBreakpointServicePlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/DebuggerLogicalBreakpointServicePlugin.java @@ -486,12 +486,7 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin } protected void forgetAllBreakpoints(RemoveCollector r) { - Collection 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); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ExceptionDataDirectory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ExceptionDataDirectory.java index c83f17665a..e3bac00458 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ExceptionDataDirectory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ExceptionDataDirectory.java @@ -90,7 +90,7 @@ public class ExceptionDataDirectory extends DataDirectory { } createDirectoryBookmark(program, addr); if (functionEntries != null) { - functionEntries.markup(program, addr); + functionEntries.markup(program, addr, log); } } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ImageRuntimeFunctionEntries.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ImageRuntimeFunctionEntries.java index 90211c7c1c..99ffba9da5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ImageRuntimeFunctionEntries.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ImageRuntimeFunctionEntries.java @@ -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; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ImageRuntimeFunctionEntries_ARM.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ImageRuntimeFunctionEntries_ARM.java index 1d87684b0a..110c34babc 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ImageRuntimeFunctionEntries_ARM.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ImageRuntimeFunctionEntries_ARM.java @@ -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; + } } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ImageRuntimeFunctionEntries_X86.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ImageRuntimeFunctionEntries_X86.java index 6206d64c48..7c9f13d013 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ImageRuntimeFunctionEntries_X86.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ImageRuntimeFunctionEntries_X86.java @@ -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; + } } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PEx64UnwindInfoDataType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PEx64UnwindInfoDataType.java index da43861fbe..83ce8b6ad6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PEx64UnwindInfoDataType.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PEx64UnwindInfoDataType.java @@ -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)) {