diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramMemoryUtil.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramMemoryUtil.java index 03eaf1567b..89a7850adb 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramMemoryUtil.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramMemoryUtil.java @@ -30,6 +30,7 @@ import ghidra.util.datastruct.ListAccumulator; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitorAdapter; +import utility.function.TerminatingConsumer; /** * ProgramMemoryUtil contains some static methods for @@ -725,7 +726,7 @@ public class ProgramMemoryUtil { } } } - + /** * Finds the string in memory indicated by the searchString limited to the indicated * memory blocks and address set. @@ -740,9 +741,36 @@ public class ProgramMemoryUtil { public static List
findString(String searchString, Program program, List blocks, AddressSetView set, TaskMonitor monitor) throws CancelledException { + + List
addresses = new ArrayList<>(); + + // just add each found location to the list, no termination of search + TerminatingConsumer
collector = (i) -> addresses.add(i); + + locateString(searchString, collector, program, blocks, set, monitor); + + return addresses; + } + + /** + * Finds the string in memory indicated by the searchString limited to the indicated + * memory blocks and address set. Each found location calls the foundLocationConsumer.consume(addr) + * method. If the search should terminate, (ie. enough results found), then terminateRequested() should + * return true. Requesting termination is different than a cancellation from the task monitor. + * + * @param searchString the string to find + * @param foundLocationConsumer location consumer with consumer.accept(Address addr) routine defined + * @param program the program to search + * @param blocks the only blocks to search + * @param set a set of the addresses to limit the results + * @param monitor a task monitor to allow + * @throws CancelledException if the user cancels + */ + public static void locateString(String searchString, TerminatingConsumer
foundLocationConsumer, Program program, + List blocks, AddressSetView set, TaskMonitor monitor) + throws CancelledException { monitor.setMessage("Finding \"" + searchString + "\"."); - List
addresses = new ArrayList<>(); int length = searchString.length(); byte[] bytes = searchString.getBytes(); Memory memory = program.getMemory(); @@ -759,7 +787,10 @@ public class ProgramMemoryUtil { break; // no more found in block. } if (set.contains(foundAddress)) { - addresses.add(foundAddress); + foundLocationConsumer.accept(foundAddress); + if (foundLocationConsumer.terminationRequested()) { + return; // termination of search requested + } } try { startAddress = foundAddress.add(length); @@ -770,7 +801,6 @@ public class ProgramMemoryUtil { } while (startAddress.compareTo(endAddress) <= 0); } - return addresses; } /** diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/TypeDescriptorModel.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/TypeDescriptorModel.java index d451bb5423..be3f76b784 100644 --- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/TypeDescriptorModel.java +++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/TypeDescriptorModel.java @@ -25,10 +25,15 @@ import ghidra.program.model.address.*; import ghidra.program.model.data.*; import ghidra.program.model.lang.UndefinedValueException; import ghidra.program.model.listing.Program; -import ghidra.program.model.mem.*; +import ghidra.program.model.mem.DumbMemBufferImpl; +import ghidra.program.model.mem.Memory; import ghidra.program.model.scalar.Scalar; import ghidra.program.model.symbol.Namespace; import ghidra.program.model.symbol.Symbol; +import ghidra.program.model.util.AddressSetPropertyMap; +import ghidra.util.exception.AssertException; +import ghidra.util.exception.CancelledException; +import ghidra.util.task.TaskMonitor; import mdemangler.*; import mdemangler.datatype.MDDataType; import mdemangler.datatype.complex.MDComplexType; @@ -248,15 +253,18 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel { * @return true if the data type has a vf table pointer. Otherwise, it has a hash value. */ private static boolean hasVFPointer(Program program) { - // Should be true when 64 bit or RTTI. - if (MSDataTypeUtils.is64Bit(program)) { + + Address typeInfoVftableAddress = null; + try { + typeInfoVftableAddress = RttiUtil.findTypeInfoVftableAddress(program, TaskMonitor.DUMMY); + } + catch (CancelledException e) { + throw new AssertException(e); + } + if (typeInfoVftableAddress != null) { return true; } - Address address = RttiUtil.getTypeInfoTypeDescriptorAddress(program); - if (address == null) { - return false; - } - return RttiUtil.isTypeInfoTypeDescriptorAddress(program, address); + return false; } /** @@ -350,9 +358,11 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel { throw new UndefinedValueException( "No vf table pointer is defined for this TypeDescriptor model."); } + + Address vfTableAddress; // component 0 is either vf table pointer or hash value. - Address vfTableAddress = - EHDataTypeUtilities.getAddress(getDataType(), VF_TABLE_OR_HASH_ORDINAL, getMemBuffer()); + vfTableAddress = EHDataTypeUtilities.getAddress(getDataType(), VF_TABLE_OR_HASH_ORDINAL, getMemBuffer()); + return vfTableAddress.getOffset() != 0 ? vfTableAddress : null; } diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/CreateVfTableBackgroundCmd.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/CreateVfTableBackgroundCmd.java index 7d4e5c1cc8..742989fbe6 100644 --- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/CreateVfTableBackgroundCmd.java +++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/CreateVfTableBackgroundCmd.java @@ -187,7 +187,7 @@ public class CreateVfTableBackgroundCmd extends AbstractCreateDataBackgroundCmd< // Create functions that are referred to by the vf table. if (applyOptions.shouldCreateFunction()) { - int elementCount = model.getCount(); + int elementCount = model.getElementCount(); for (int tableElementIndex = 0; tableElementIndex < elementCount; tableElementIndex++) { monitor.checkCanceled(); Address vfPointer = model.getVirtualFunctionPointer(tableElementIndex); diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/RttiUtil.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/RttiUtil.java index ac9edf913b..838e871ea9 100644 --- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/RttiUtil.java +++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/RttiUtil.java @@ -15,16 +15,14 @@ */ package ghidra.app.cmd.data.rtti; -import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.getAbsoluteAddress; +import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.*; -import java.io.IOException; -import java.util.List; +import java.util.*; import ghidra.app.cmd.data.TypeDescriptorModel; import ghidra.app.util.NamespaceUtils; import ghidra.app.util.PseudoDisassembler; -import ghidra.app.util.bin.BinaryReader; -import ghidra.app.util.bin.MemoryByteProvider; +import ghidra.app.util.datatype.microsoft.MSDataTypeUtils; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSetView; import ghidra.program.model.listing.GhidraClass; @@ -34,20 +32,23 @@ import ghidra.program.model.mem.MemoryBlock; import ghidra.program.model.symbol.*; import ghidra.program.util.ProgramMemoryUtil; import ghidra.util.Msg; -import ghidra.util.exception.AssertException; -import ghidra.util.exception.CancelledException; -import ghidra.util.exception.InvalidInputException; +import ghidra.util.exception.*; import ghidra.util.task.TaskMonitor; +import utility.function.TerminatingConsumer; /** * RttiUtil provides constants and static methods for processing RTTI information. */ public class RttiUtil { + private static final String TYPE_INFO_NAMESPACE = "type_info"; + private static final int MIN_MATCHING_VFTABLE_PTRS = 5; static final String CONST_PREFIX = "const "; - public static final String TYPE_INFO_STRING = ".?AVtype_info@@"; + public static final String TYPE_INFO_LABEL = "class_type_info_RTTI_Type_Descriptor"; - private static final String MANGLED_TYPE_INFO_SYMBOL = "??_R0?AVtype_info@@@8"; + public static final String TYPE_INFO_STRING = ".?AVtype_info@@"; + private static final String CLASS_PREFIX_CHARS = ".?A"; + private static Map vftableMap = new WeakHashMap<>(); private RttiUtil() { // utility class; can't create @@ -151,6 +152,12 @@ public class RttiUtil { : false) { break; // Not pointing to text section. } + + // any references after the first one ends the table + if (tableSize > 0 && program.getReferenceManager().hasReferencesTo(currentVfPointerAddress)) { + break; + } + if (!pseudoDisassembler.isValidSubroutine(referencedAddress, true)) { break; // Not pointing to possible function. } @@ -178,63 +185,185 @@ public class RttiUtil { } /** - * Gets the address of the base type_info structure in the provided program. - * The descriptor will only be manually located if {@value TYPE_INFO_STRING} is present. - * @param program the program - * @return the address of the type_info structure or null if not found + * Identify common TypeInfo address through examination of discovered VtTables */ - public static Address getTypeInfoTypeDescriptorAddress(Program program) { - SymbolTable table = program.getSymbolTable(); - List symbols = table.getGlobalSymbols(TYPE_INFO_LABEL); - if (symbols.isEmpty()) { - symbols = table.getGlobalSymbols(MANGLED_TYPE_INFO_SYMBOL); + private static class CommonRTTIMatchCounter implements TerminatingConsumer
{ + int matchingAddrCount = 0; + int defaultPointerSize = 4; + boolean terminationRequest = false; + Address commonVftableAddress = null; + Program program; + + public CommonRTTIMatchCounter(Program program) { + this.program = program; + defaultPointerSize = program.getDefaultPointerSize(); } - if (!symbols.isEmpty()) { - for (Symbol symbol : symbols) { - if (isTypeInfoTypeDescriptorAddress(program, symbol.getAddress())) { - return symbol.getAddress(); - } - } + + public Address getinfoVfTable() { + return commonVftableAddress; } - return locateTypeInfoAddress(program); - } - /** - * Checks if the provided address is a TypeDescriptor containing the - * {@value TYPE_INFO_STRING} component - * @param program the program - * @param address the descriptor address - * @return true if {@value TYPE_INFO_STRING} is present in the descriptor at the address - */ - public static boolean isTypeInfoTypeDescriptorAddress(Program program, Address address) { - MemoryByteProvider provider = new MemoryByteProvider(program.getMemory(), address); - try { - BinaryReader reader = new BinaryReader(provider, !program.getLanguage().isBigEndian()); - String value = reader.readAsciiString(program.getDefaultPointerSize() * 2); - return TYPE_INFO_STRING.equals(value); - } catch (IOException e) { - return false; + @Override + public boolean terminationRequested() { + return terminationRequest; + } + + @Override + public void accept(Address foundAddress) { + Address mangledClassNameAddress = foundAddress; + + Address pointerToTypeInfoVftable = + mangledClassNameAddress.subtract(2 * defaultPointerSize); + + Address possibleVftableAddress = + MSDataTypeUtils.getAbsoluteAddress(program, pointerToTypeInfoVftable); + if (possibleVftableAddress == null) { + return; // valid address not found + } + if (possibleVftableAddress.getOffset() == 0) { + return; // don't want zero_address to count + } + // if ever we find one that doesn't match, start count over + if (!possibleVftableAddress.equals(commonVftableAddress)) { + if (matchingAddrCount > 2) { + return; // already have more than one match, assume this one was outlier, ignore + } + matchingAddrCount = 0; + } + + commonVftableAddress = possibleVftableAddress; + matchingAddrCount++; + + if (matchingAddrCount > MIN_MATCHING_VFTABLE_PTRS) { + // done finding good addresses have at Minimum matching number + terminationRequest = true; + return; + } + return; } } - private static Address locateTypeInfoAddress(Program program) { - Memory memory = program.getMemory(); - try { - List dataBlocks = ProgramMemoryUtil.getMemoryBlocksStartingWithName( - program, program.getMemory(), ".data", TaskMonitor.DUMMY); - for (MemoryBlock memoryBlock : dataBlocks) { - Address typeInfoAddress = - memory.findBytes(memoryBlock.getStart(), memoryBlock.getEnd(), - TYPE_INFO_STRING.getBytes(), null, true, TaskMonitor.DUMMY); - if (typeInfoAddress != null) { - return TypeDescriptorModel.getBaseAddress(program, typeInfoAddress); - } - } - } catch (CancelledException e) { - // impossible - throw new AssertException(e); + /** + * Method to figure out the type_info vftable address using pointed to value by all RTTI classes + * @param program the current program + * @param monitor the TaskMonitor + * @return the type_info address or null if it cannot be determined + * @throws CancelledException if cancelled + */ + public static Address findTypeInfoVftableAddress(Program program, TaskMonitor monitor) + throws CancelledException { + + // Checked for cached value + if (vftableMap.containsKey(program)) { + return vftableMap.get(program); } + + // if type info vftable already a symbol, just use the address of the symbol + Address infoVftableAddress = findTypeInfoVftableLabel(program); + if (infoVftableAddress == null) { + + // search for mangled class prefix names, and locate the vftable pointer relative to some + // minimum number that all point to the same location which should be the vftable + AddressSetView set = program.getMemory().getLoadedAndInitializedAddressSet(); + List dataBlocks = + ProgramMemoryUtil.getMemoryBlocksStartingWithName(program, set, ".data", monitor); + + CommonRTTIMatchCounter vfTableAddrChecker = new CommonRTTIMatchCounter(program); + + ProgramMemoryUtil.locateString(CLASS_PREFIX_CHARS, vfTableAddrChecker, program, + dataBlocks, set, monitor); + infoVftableAddress = vfTableAddrChecker.getinfoVfTable(); + } + + // cache result of search + vftableMap.put(program, infoVftableAddress); + + return infoVftableAddress; + } + + /** + * find type info vftable by existing type_info::vftable symbol + * @param program program to check + * @return return vftable addr if symbol exists + */ + private static Address findTypeInfoVftableLabel(Program program) { + SymbolTable symbolTable = program.getSymbolTable(); + Namespace typeinfoNamespace = + symbolTable.getNamespace(TYPE_INFO_NAMESPACE, program.getGlobalNamespace()); + Symbol vftableSymbol = + symbolTable.getLocalVariableSymbol("vftable", typeinfoNamespace); + if (vftableSymbol != null) { + return vftableSymbol.getAddress(); + } + + vftableSymbol = symbolTable.getLocalVariableSymbol("`vftable'", typeinfoNamespace); + if (vftableSymbol != null) { + return vftableSymbol.getAddress(); + } + + vftableSymbol = symbolTable.getLocalVariableSymbol("type_info", typeinfoNamespace); + if (vftableSymbol != null) { + return vftableSymbol.getAddress(); + } + return null; } + /** + * Method to create type_info vftable label (and namespace if needed) at the given address + * @param program the current program + * @param address the given address + */ + public static void createTypeInfoVftableSymbol(Program program, Address address) { + + SymbolTable symbolTable = program.getSymbolTable(); + + Namespace typeinfoNamespace = + symbolTable.getNamespace(TYPE_INFO_NAMESPACE, program.getGlobalNamespace()); + + if (typeinfoNamespace == null) { + try { + typeinfoNamespace = symbolTable.createClass(program.getGlobalNamespace(), + TYPE_INFO_NAMESPACE, SourceType.IMPORTED); + } + catch (DuplicateNameException e) { + Msg.error(RttiUtil.class, "Duplicate type_info class namespace at " + + program.getName() + " " + address + ". " + e.getMessage()); + return; + } + catch (InvalidInputException e) { + Msg.error(RttiUtil.class, "Invalid input creating type_info class namespace " + + program.getName() + " " + address + ". " + e.getMessage()); + return; + } + } + + // check to see if symbol already exists both non-pdb and pdb versions + Symbol vftableSymbol = symbolTable.getSymbol(TYPE_INFO_NAMESPACE, address, typeinfoNamespace); + if (vftableSymbol != null) { + return; + } + + vftableSymbol = symbolTable.getSymbol("`vftable'", address, typeinfoNamespace); + if (vftableSymbol != null) { + return; + } + + try { + vftableSymbol = + symbolTable.createLabel(address, "vftable", typeinfoNamespace, SourceType.IMPORTED); + if (vftableSymbol == null) { + Msg.error(RttiUtil.class, + program.getName() + " Couldn't create type_info vftable symbol. "); + return; + } + } + catch (InvalidInputException e) { + Msg.error(RttiUtil.class, + program.getName() + " Couldn't create type_info vftable symbol. " + e.getMessage()); + return; + } + + } + } diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/VfTableModel.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/VfTableModel.java index 844933af14..636608aa02 100644 --- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/VfTableModel.java +++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/VfTableModel.java @@ -44,6 +44,7 @@ public class VfTableModel extends AbstractCreateDataTypeModel { private Program lastProgram; private DataType lastDataType; private int lastElementCount = -1; + private int elementCount = 0; /** * Creates the model for the vf table data. @@ -54,8 +55,18 @@ public class VfTableModel extends AbstractCreateDataTypeModel { */ public VfTableModel(Program program, Address vfTableAddress, DataValidationOptions validationOptions) { - super(program, RttiUtil.getVfTableCount(program, vfTableAddress), vfTableAddress, + // use one for the data type element count, because there is only one array of some element size + super(program, 1, vfTableAddress, validationOptions); + elementCount= RttiUtil.getVfTableCount(program, vfTableAddress); + } + + /** + * Get the number of vftable elements in this vftable + * @return number of elements + */ + public int getElementCount() { + return elementCount; } @Override @@ -79,7 +90,7 @@ public class VfTableModel extends AbstractCreateDataTypeModel { long entrySize = individualEntryDataType.getLength(); // Each entry is a pointer to where a function can possibly be created. - long numEntries = getCount(); + long numEntries = elementCount; if (numEntries == 0) { throw new InvalidDataTypeException( getName() + " data type at " + getAddress() + " doesn't have a valid vf table."); @@ -120,9 +131,8 @@ public class VfTableModel extends AbstractCreateDataTypeModel { lastProgram = program; lastDataType = null; - lastElementCount = -1; - - lastElementCount = getCount(); + lastElementCount = elementCount; + if (lastElementCount > 0) { DataTypeManager dataTypeManager = program.getDataTypeManager(); PointerDataType pointerDt = new PointerDataType(dataTypeManager); diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/plugin/prototype/MicrosoftCodeAnalyzerPlugin/RttiAnalyzer.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/plugin/prototype/MicrosoftCodeAnalyzerPlugin/RttiAnalyzer.java index 3515682b6d..6578e55ffb 100644 --- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/plugin/prototype/MicrosoftCodeAnalyzerPlugin/RttiAnalyzer.java +++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/plugin/prototype/MicrosoftCodeAnalyzerPlugin/RttiAnalyzer.java @@ -19,18 +19,14 @@ import java.util.*; import ghidra.app.cmd.data.CreateTypeDescriptorBackgroundCmd; import ghidra.app.cmd.data.TypeDescriptorModel; -import ghidra.app.cmd.data.rtti.CreateRtti4BackgroundCmd; -import ghidra.app.cmd.data.rtti.Rtti4Model; -import ghidra.app.cmd.data.rtti.RttiUtil; +import ghidra.app.cmd.data.rtti.*; import ghidra.app.services.*; import ghidra.app.util.datatype.microsoft.*; import ghidra.app.util.importer.MessageLog; import ghidra.program.model.address.*; import ghidra.program.model.data.InvalidDataTypeException; -import ghidra.program.model.lang.UndefinedValueException; import ghidra.program.model.listing.Program; import ghidra.program.model.mem.MemoryBlock; -import ghidra.program.model.symbol.SourceType; import ghidra.program.util.ProgramMemoryUtil; import ghidra.util.bytesearch.*; import ghidra.util.exception.*; @@ -77,48 +73,47 @@ public class RttiAnalyzer extends AbstractAnalyzer { public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) throws CancelledException { - Address typeInfoRtti0Address = RttiUtil.getTypeInfoTypeDescriptorAddress(program); - if (typeInfoRtti0Address == null) { - log.appendMsg(this.getName(), "Couldn't find RTTI type info structure."); + Address commonVfTableAddress = RttiUtil.findTypeInfoVftableAddress(program, monitor); + + if (commonVfTableAddress == null) { return true; } - // ensure the label is present - try { - program.getSymbolTable().createLabel( - typeInfoRtti0Address, RttiUtil.TYPE_INFO_LABEL, SourceType.ANALYSIS); - } catch (InvalidInputException e) { - // not invalid - throw new AssertException(e); - } - - // Get the address of the vf table data in common for all RTTI 0. - TypeDescriptorModel typeDescriptorModel = - new TypeDescriptorModel(program, typeInfoRtti0Address, validationOptions); - try { - Address commonVfTableAddress = typeDescriptorModel.getVFTableAddress(); - if (commonVfTableAddress == null) { - log.appendMsg(this.getName(), - "Couldn't get vf table address for RTTI 0 @ " + typeInfoRtti0Address + ". "); - return false; - } - - int alignment = program.getDefaultPointerSize(); - List dataBlocks = ProgramMemoryUtil.getMemoryBlocksStartingWithName( - program, program.getMemory(), ".data", TaskMonitor.DUMMY); - Set
possibleTypeAddresses = ProgramMemoryUtil.findDirectReferences(program, - dataBlocks, alignment, commonVfTableAddress, monitor); - - // We now have a list of potential rtti0 addresses. - processRtti0(possibleTypeAddresses, program, monitor); - + RttiUtil.createTypeInfoVftableSymbol(program,commonVfTableAddress); + + Set
possibleTypeAddresses = locatePotentialRTTI0Entries(program, set, monitor); + if (possibleTypeAddresses == null) { return true; } - catch (InvalidDataTypeException | UndefinedValueException e) { - log.appendMsg(this.getName(), "Couldn't get vf table address for RTTI 0 @ " + - typeInfoRtti0Address + ". " + e.getMessage()); - return false; + + // We now have a list of potential rtti0 addresses. + processRtti0(possibleTypeAddresses, program, monitor); + + return true; + } + + /** + * locate any potential RTTI0 based on pointers to the type_info vftable + * @param program proram to locate within + * @param set restricted set to locate within + * @param monitor monitor for canceling + * @return set of potential RTTI0 entries + * @throws CancelledException + */ + private Set
locatePotentialRTTI0Entries(Program program, AddressSetView set, + TaskMonitor monitor) throws CancelledException { + Address commonVfTableAddress = RttiUtil.findTypeInfoVftableAddress(program, monitor); + if (commonVfTableAddress == null) { + return null; } + + // use the type_info vftable address to find a list of potential RTTI0 addresses + int alignment = program.getDefaultPointerSize(); + List dataBlocks = ProgramMemoryUtil.getMemoryBlocksStartingWithName( + program, program.getMemory(), ".data", TaskMonitor.DUMMY); + Set
possibleTypeAddresses = ProgramMemoryUtil.findDirectReferences(program, + dataBlocks, alignment, commonVfTableAddress, monitor); + return possibleTypeAddresses; } private void processRtti0(Collection
possibleRtti0Addresses, Program program, @@ -168,6 +163,9 @@ public class RttiAnalyzer extends AbstractAnalyzer { dataBlocks.addAll(ProgramMemoryUtil.getMemoryBlocksStartingWithName(program, program.getMemory(), ".data", monitor)); + dataBlocks.addAll(ProgramMemoryUtil.getMemoryBlocksStartingWithName(program, + program.getMemory(), ".text", monitor)); + List
rtti4Addresses = getRtti4Addresses(program, dataBlocks, rtti0Locations, validationOptions, monitor); diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/test/java/ghidra/app/cmd/data/rtti/AbstractRttiTest.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/test/java/ghidra/app/cmd/data/rtti/AbstractRttiTest.java index e94aec885e..85fa51c2f5 100644 --- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/test/java/ghidra/app/cmd/data/rtti/AbstractRttiTest.java +++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/test/java/ghidra/app/cmd/data/rtti/AbstractRttiTest.java @@ -269,7 +269,7 @@ class AbstractRttiTest extends AbstractCreateDataTypeModelTest { vfTableModel.validate(); assertEquals(addressVfTable, vfTableModel.getAddress()); int numVfTableEntries = vfAddresses.length; - assertEquals(numVfTableEntries, vfTableModel.getCount()); + assertEquals(numVfTableEntries, vfTableModel.getElementCount()); for (int i = 0; i < numVfTableEntries; i++) { assertEquals(addr(program, vfAddresses[i]), vfTableModel.getVirtualFunctionPointer(i)); } diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/test/java/ghidra/app/cmd/data/rtti/RttiModelTest.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/test/java/ghidra/app/cmd/data/rtti/RttiModelTest.java index 988e88f43a..481e8e728f 100644 --- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/test/java/ghidra/app/cmd/data/rtti/RttiModelTest.java +++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/test/java/ghidra/app/cmd/data/rtti/RttiModelTest.java @@ -51,7 +51,7 @@ public class RttiModelTest extends AbstractRttiTest { setupRtti4_32(builder, 0x01001340L, 0, 0, 0, "0x01005364", "0x0100137c"); Address address = builder.addr(0x01001340L); checkInvalidModel(new Rtti4Model(program, address, defaultValidationOptions), - "TypeDescriptor data type at 01005364 doesn't point to a vfTable address in a loaded and initialized memory block."); + "No vf table pointer is defined for this TypeDescriptor model."); } @Test @@ -62,7 +62,7 @@ public class RttiModelTest extends AbstractRttiTest { setupRtti0_32(builder, 0x01001364, "0x01007700", "0x0", "stuff"); Address address = builder.addr(0x01001340L); checkInvalidModel(new Rtti4Model(program, address, defaultValidationOptions), - "TypeDescriptor data type at 01001364 doesn't point to a vfTable address in a loaded and initialized memory block."); + "No vf table pointer is defined for this TypeDescriptor model."); } @Test diff --git a/Ghidra/Framework/Utility/src/main/java/utility/function/TerminatingConsumer.java b/Ghidra/Framework/Utility/src/main/java/utility/function/TerminatingConsumer.java new file mode 100644 index 0000000000..6f5e2cf104 --- /dev/null +++ b/Ghidra/Framework/Utility/src/main/java/utility/function/TerminatingConsumer.java @@ -0,0 +1,33 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package utility.function; + +import java.util.function.Consumer; + +/** + * TerminatingConsumer is a Consumer {@link Consumer} that can request termination + * of the supplier once some condition is reached, for example some number of consumed results + * accepted. If termination is required override the terminationRequested() + * method to return true when termination state is reached. + * + * @param the type of the input to the operation + */ +public interface TerminatingConsumer extends Consumer { + + default boolean terminationRequested() { + return false; + } +}