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;
+ }
+}