GP-1408 Changed inheriting class structures to contain individual base class structure components instead of whole structures. This allows correct class vftable and vbtable pointers to be used instead of base class ones. This makes structures messier but makes decompiler usage correct. Also updated methods that update virtual functions.

This commit is contained in:
ghidra007 2021-11-09 14:56:19 +00:00
parent 513c9beb9d
commit a8e39d58c4
2 changed files with 628 additions and 74 deletions

View file

@ -1305,7 +1305,14 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
recoveredClass.setHasMultipleVirtualInheritance(true);
}
}
//TODO: CHD_AMBIGUOUS = 0x00000004;
//TODO: update class to handle this type
if ((inheritanceType & CHD_AMBIGUOUS) == CHD_AMBIGUOUS) {
recoveredClass.setHasSingleInheritance(false);
recoveredClass.setHasMultipleInheritance(true);
Msg.debug(this, recoveredClass.getName() + " has ambiguous inh type");
}
}
@ -2231,7 +2238,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
// create current class structure and add pointer to vftable, all parent member data strutures, and class member data structure
Structure classStruct = null;
classStruct = createClassStructureUsingRTTI(recoveredClass, vfPointerDataTypes);
classStruct = createClassStructureUsingRTTI(recoveredClass,
vfPointerDataTypes);
applyVbtableStructure(recoveredClass);
@ -2271,7 +2279,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
* @return the created class structure data type
* @throws Exception if invalid data creation
*/
//NEW
private Structure createClassStructureUsingRTTI(RecoveredClass recoveredClass,
Map<Address, DataType> vfPointerDataTypes) throws Exception {
@ -2302,8 +2310,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
// if cannot recover the base class array return the existing or computed one instead
// so user will at least have some information like correct size and some members
if (baseClassArrayData == null) {
classStructureDataType =
createDefaultStructure(classStructure, classStructureDataType);
classStructureDataType = createDefaultStructure(classStructure, classStructureDataType);
return classStructureDataType;
}
@ -2312,7 +2319,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
if (recoveredClass.getClassHierarchyMap().size() > 1 &&
recoveredClass.hasMultipleVirtualInheritance()) {
classStructureDataType =
addVbtableToClassStructure(recoveredClass, classStructureDataType);
addVbtableToClassStructure(recoveredClass, classStructureDataType, false);
}
int baseClassOffset = 0;
@ -2345,11 +2352,10 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
}
// get the baseClassStructure (ie self or ancestor class) and its displacement values
Structure baseClassStructure =
getClassStructureFromDataTypeManager(baseClass);
Structure baseClassStructure = getClassStructureFromDataTypeManager(baseClass);
if (baseClassStructure == null) {
// println("****recovered Class = " + recoveredClass.getName() + "'s base Class " +
// baseClass.getName() + " class struct is null");
Msg.debug(this, "****recovered Class = " + recoveredClass.getName() +
"'s base Class " + baseClass.getName() + " class struct is null");
continue;
}
@ -2376,8 +2382,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
recoveredClass.getVftableAddresses().size() > 1 &&
recoveredClass.inheritsVirtualAncestor()) {
int offsetOfVirtualParent =
getOffsetOfVirtualParent(recoveredClass, baseClassStructure);
//NEW
int offsetOfVirtualParent = getSingleVirtualParentOffset(baseClass);
int dataLength;
if (offsetOfVirtualParent == NONE) {
@ -2389,8 +2395,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
dataLength = baseClassStructure.getLength() - lengthOfVirtualParent;
}
if (structUtils.canAdd(classStructureDataType, baseClassOffset,
dataLength, monitor)) {
if (structUtils.canAdd(classStructureDataType, baseClassOffset, dataLength,
monitor)) {
classStructureDataType =
addIndividualComponentsToStructure(classStructureDataType,
baseClassStructure, baseClassOffset, offsetOfVirtualParent);
@ -2401,9 +2407,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
// else copy whole baseClass structure to the class Structure
if (structUtils.canAdd(classStructureDataType, baseClassOffset,
baseClassStructure.getLength(), monitor)) {
classStructureDataType = structUtils.addDataTypeToStructure(
classStructureDataType, baseClassOffset, baseClassStructure,
baseClassStructure.getName(), monitor);
classStructureDataType =
structUtils.addDataTypeToStructure(classStructureDataType, baseClassOffset,
baseClassStructure, baseClassStructure.getName(), monitor);
}
@ -2421,9 +2427,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
if (structUtils.canAdd(classStructureDataType, baseClassOffset,
baseClassStructure.getLength(), monitor)) {
classStructureDataType = structUtils.addDataTypeToStructure(
classStructureDataType, baseClassOffset, baseClassStructure,
baseClassStructure.getName(), monitor);
classStructureDataType =
structUtils.addDataTypeToStructure(classStructureDataType, baseClassOffset,
baseClassStructure, baseClassStructure.getName(), monitor);
}
}
@ -2432,8 +2438,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
if (vfPointerDataTypes != null) {
if (!isClassOffsetToVftableMapComplete(recoveredClass)) {
// println("class vftable offset map for " + recoveredClass.getName() +
// " is not complete");
Msg.debug(this, "class vftable offset map for " + recoveredClass.getName() +
" is not complete");
}
// iterate over the set of offsets to vftables for the class and if nothing
@ -2452,9 +2458,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
if (structUtils.canAdd(classStructureDataType, offset.intValue(),
classVftablePointer.getLength(), monitor)) {
classStructureDataType = structUtils.addDataTypeToStructure(
classStructureDataType, offset.intValue(), classVftablePointer,
CLASS_VTABLE_PTR_FIELD_EXT, monitor);
classStructureDataType = structUtils.addDataTypeToStructure(classStructureDataType,
offset.intValue(), classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor);
}
}
@ -2462,36 +2467,43 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
// add the vbtable structure for single inheritance/virt parent case
if (recoveredClass.hasSingleInheritance() && recoveredClass.inheritsVirtualAncestor()) {
classStructureDataType =
addVbtableToClassStructure(recoveredClass, classStructureDataType);
addVbtableToClassStructure(recoveredClass, classStructureDataType, false);
}
//NEW
int dataOffset = getDataOffset(recoveredClass, classStructureDataType);
int dataLen = UNKNOWN;
if (dataOffset != NONE) {
dataLen = structUtils.getNumberOfUndefinedsStartingAtOffset(
classStructureDataType, dataOffset, monitor);
dataLen = structUtils.getNumberOfUndefinedsStartingAtOffset(classStructureDataType,
dataOffset, monitor);
}
if (dataLen != UNKNOWN && dataLen > 0) {
Structure recoveredClassDataStruct =
createClassMemberDataStructure(recoveredClass,
Structure recoveredClassDataStruct = createClassMemberDataStructure(recoveredClass,
classStructureDataType, dataLen, dataOffset);
if (recoveredClassDataStruct != null) {
classStructureDataType = structUtils.addDataTypeToStructure(
classStructureDataType, dataOffset, recoveredClassDataStruct, "data", monitor);
classStructureDataType = structUtils.addDataTypeToStructure(classStructureDataType,
dataOffset, recoveredClassDataStruct,
classStructureDataType.getName() + "_data", monitor);
}
}
if (classStructureDataType.getNumComponents() == classStructureDataType
.getNumDefinedComponents()) {
//NEW:
classStructureDataType =
addClassVftables(classStructureDataType, recoveredClass, vfPointerDataTypes);
//NEW:
classStructureDataType =
addVbtableToClassStructure(recoveredClass, classStructureDataType, true);
if (classStructureDataType.getNumComponents() == classStructureDataType.getNumDefinedComponents()) {
classStructureDataType.setPackingEnabled(true);
}
classStructureDataType.setDescription(
createParentStringBuffer(recoveredClass).toString());
classStructureDataType.setDescription(createParentStringBuffer(recoveredClass).toString());
classStructureDataType = (Structure) dataTypeManager.addDataType(classStructureDataType,
DataTypeConflictHandler.DEFAULT_HANDLER);
@ -2499,6 +2511,267 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
return classStructureDataType;
}
private Structure addClassVftables(Structure classStructureDataType,
RecoveredClass recoveredClass, Map<Address, DataType> vfPointerDataTypes)
throws CancelledException, IllegalArgumentException {
if (vfPointerDataTypes == null) {
return classStructureDataType;
}
if (!isClassOffsetToVftableMapComplete(recoveredClass)) {
Msg.debug(this,
"class vftable offset map for " + recoveredClass.getName() + " is not complete");
}
// iterate over the set of offsets to vftables for the class and if nothing
// is already at the offset, add the vftables
Map<Integer, Address> classOffsetToVftableMap = recoveredClass.getClassOffsetToVftableMap();
Set<Integer> classVftableOffsets = classOffsetToVftableMap.keySet();
if (classVftableOffsets.isEmpty()) {
return classStructureDataType;
}
for (Integer offset : classVftableOffsets) {
monitor.checkCanceled();
Address vftableAddress = classOffsetToVftableMap.get(offset);
int vftableOffset = offset.intValue();
DataType classVftablePointer = vfPointerDataTypes.get(vftableAddress);
boolean addedVftablePointer = false;
while (!addedVftablePointer) {
monitor.checkCanceled();
// if enough empty bytes - add class vftable pointer
if (structUtils.canAdd(classStructureDataType, vftableOffset,
classVftablePointer.getLength(), monitor)) {
classStructureDataType =
structUtils.addDataTypeToStructure(classStructureDataType, vftableOffset,
classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor);
addedVftablePointer = true;
continue;
}
// if already has a base class vftable pointer replace with main class vftablePtr
// get the item at that location
//NOTE: this returns the component containing that offset so need to get the
// offset of the start of the component
//TODO: maybe updated to getComponentContaining
DataTypeComponent currentComponent =
classStructureDataType.getComponentAt(vftableOffset);
int componentOffset = currentComponent.getOffset();
if (currentComponent.getFieldName().endsWith(CLASS_VTABLE_PTR_FIELD_EXT)) {
classStructureDataType.replaceAtOffset(vftableOffset, classVftablePointer,
classVftablePointer.getLength(), CLASS_VTABLE_PTR_FIELD_EXT, "");
addedVftablePointer = true;
continue;
}
// ToDO: check size first
if (!(currentComponent.getDataType() instanceof Structure)) {
// Msg.debug(this,
// "Overwriting non-empty, non-vftable, non-struct at offset " +
// offset.intValue() + " of " + classStructureDataType.getName());
classStructureDataType.replaceAtOffset(vftableOffset, classVftablePointer,
classVftablePointer.getLength(), CLASS_VTABLE_PTR_FIELD_EXT, "");
addedVftablePointer = true;
continue;
}
// if there is a structure at the offset, split it into pieces then
// loop again to try to place vftable over either empty bytes or base vftableptr
if (currentComponent.getDataType() instanceof Structure) {
DataType currentDT = currentComponent.getDataType();
Structure internalStruct = (Structure) currentDT;
int sizeBefore = internalStruct.getLength();
internalStruct = splitStructure(internalStruct);
int sizeAfter = internalStruct.getLength();
if (sizeBefore != sizeAfter) {
Msg.debug(this,
"Splitting internal Struct " + internalStruct.getName() + " in " +
classStructureDataType.getName() + " at offset " +
offset.intValue());
}
DataTypeComponent[] components = internalStruct.getComponents();
for (DataTypeComponent component : components) {
int innerOffset = component.getOffset();
int replaceOffset = component.getOffset() + componentOffset;
if (classStructureDataType.getLength() <= replaceOffset) {
Msg.debug(this,
classStructureDataType.getName() + " trying to place component " +
component.getFieldName() + " at offset " +
component.getOffset());
}
// add indiv components of internal structure to the outer structure
classStructureDataType.replaceAtOffset(componentOffset + innerOffset,
component.getDataType(), component.getLength(),
component.getFieldName(), "");
}
}
}
}
return classStructureDataType;
}
private Structure splitStructure(Structure structure)
throws CancelledException, IllegalArgumentException {
structure.setPackingEnabled(false);
if (structure.isNotYetDefined() || isEmptyDefaultSizeStructure(structure)) {
DataType undefinedDataType = new Undefined4DataType();
if (defaultPointerSize == 8) {
undefinedDataType = new Undefined8DataType();
}
structure.replaceAtOffset(0, undefinedDataType, undefinedDataType.getLength(),
structure.getName() + "_expanded", "");
}
else {
DataTypeComponent[] interalStructComponents = structure.getComponents();
// add indiv components of internal structure to the outer structure
for (DataTypeComponent component : interalStructComponents) {
structure.replaceAtOffset(component.getOffset(), component.getDataType(),
component.getLength(), component.getFieldName(), "");
}
}
if (structure.getNumComponents() == structure.getNumDefinedComponents()) {
structure.setPackingEnabled(true);
}
return structure;
}
private boolean isEmptyDefaultSizeStructure(Structure structure) throws CancelledException {
if (structure.getLength() != defaultPointerSize) {
return false;
}
int numUndefined1s =
structUtils.getNumberOfUndefinedsStartingAtOffset(structure, 0, monitor);
if (structure.getLength() == numUndefined1s) {
return true;
}
return false;
}
/**
* Method to return the offset of the given class's single virtual parent
* @param recoveredClass the given class
* @return the offset of the single virtual parent or null if there is not a single virtual parent
* or if there is no mapping in the offset map for that parent
* @throws CancelledException if cancelled
*/
public Integer getSingleVirtualParentOffset(RecoveredClass recoveredClass)
throws CancelledException {
List<RecoveredClass> virtualParentClasses = getVirtualParentClasses(recoveredClass);
if (virtualParentClasses.size() != 1) {
return null;
}
Map<RecoveredClass, Integer> parentOffsetMap = getBaseClassOffsetMap(recoveredClass);
return parentOffsetMap.get(virtualParentClasses.get(0));
}
private Map<RecoveredClass, Integer> getBaseClassOffsetMap(RecoveredClass recoveredClass)
throws CancelledException {
Map<RecoveredClass, Integer> parentOffsetMap = new HashMap<RecoveredClass, Integer>();
Data baseClassArrayData = getBaseClassArray(recoveredClass);
int baseClassOffset = 0;
int numPointers = baseClassArrayData.getNumComponents();
for (int i = 0; i < numPointers; ++i) {
monitor.checkCanceled();
// Get the base class it is pointing to
Address pointerAddress = baseClassArrayData.getComponent(i).getAddress();
Address baseClassDescriptorAddress =
extraUtils.getReferencedAddress(pointerAddress, true);
if (baseClassDescriptorAddress == null) {
continue;
}
try {
RecoveredClass baseClass =
getClassFromBaseClassDescriptor(baseClassDescriptorAddress);
if (baseClass == null) {
// TODO: msg and return null
continue;
}
// Continue if the class has mult inh but base class is not on the parent list
//TODO: possibly update to include all base classes
if (!recoveredClass.getParentList().contains(baseClass)) {
continue;
}
int mdisp = api.getInt(baseClassDescriptorAddress.add(8));
int pdisp = api.getInt(baseClassDescriptorAddress.add(12));
int vdisp = api.getInt(baseClassDescriptorAddress.add(16));
if (pdisp == -1) {
baseClassOffset = mdisp;
}
else {
// else need to fill in the virtually inherited ones
// get the offset of this base class in the class using the vbtable
Address vbtableAddress = recoveredClass.getVbtableAddress();
if (vbtableAddress == null) {
Msg.error(this,
"Cannot retrieve vbtable address so cannot create base class offset map for class " +
recoveredClass.getName());
return null;
}
baseClassOffset =
api.getInt(recoveredClass.getVbtableAddress().add(vdisp)) + pdisp;
}
parentOffsetMap.put(baseClass, baseClassOffset);
}
catch (MemoryAccessException | AddressOutOfBoundsException e) {
Msg.error(this,
"Cannot create base class offset map for class " + recoveredClass.getName());
return null;
}
}
return parentOffsetMap;
}
/**
* Method to retrieve the given class's base class array data type from the RTTI data
* @param recoveredClass the given class
@ -2553,7 +2826,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
* @throws CancelledException if cancelled
*/
private Structure addVbtableToClassStructure(RecoveredClass recoveredClass,
Structure classStructureDataType) throws CancelledException {
Structure classStructureDataType, boolean overwrite) throws CancelledException {
Structure vbtableStructure = recoveredClass.getVbtableStructure();
@ -2570,6 +2843,10 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
vbtableOffset, vbaseStructPointer, "vbtablePtr", monitor);
}
else if (overwrite) {
classStructureDataType.replaceAtOffset(vbtableOffset, vbaseStructPointer,
vbaseStructPointer.getLength(), "vbtablePtr", "");
}
}
return classStructureDataType;
}

View file

@ -2941,7 +2941,6 @@ public class RecoveredClassUtils {
// if there is already a structure created there and it is
// contained in the ClassDataTypes folder then it has already been processed so skip it
// TODO: can this be checked using the folderpath not the folder name?
if (vftableData.isStructure()) {
String[] pathElements = vftableData.getDataType().getCategoryPath().getPathElements();
if ((pathElements.length > 0) && (pathElements[0].equals(DTM_CLASS_DATA_FOLDER_NAME))) {
@ -4498,7 +4497,6 @@ public class RecoveredClassUtils {
// this is null when there is a class from somewhere other than RTTI so it is
// not stored in the map. Just use the parent namespace name in this case
// TODO: can check against other program namespace names to see if it can be shortened
if (vfunctionClass == null) {
classCommentPrefix = parentNamespace.getName();
}
@ -4787,7 +4785,8 @@ public class RecoveredClassUtils {
private PointerDataType createFunctionSignaturePointerDataType(Function vfunction,
CategoryPath classPath) throws DuplicateNameException {
FunctionDefinition functionDataType = (FunctionDefinitionDataType) vfunction.getSignature();
FunctionDefinition functionDataType =
(FunctionDefinitionDataType) vfunction.getSignature();
DataType returnType = vfunction.getReturnType();
@ -5289,12 +5288,36 @@ public class RecoveredClassUtils {
return structureDataType;
}
// This is to distinguish between class items and parent items in classes that
// have individual components of the parent split out and added to them and not just
// the whole parent structure added to them
// TODO: add method to get class obj using from the name of the structure
// so i can get the shortened class name if a template and put that here instead
String fieldname = structureToAdd.getName() + "_" + dataTypeComponent.getFieldName();
String fieldname = dataTypeComponent.getFieldName();
structureDataType = structUtils.addDataTypeToStructure(structureDataType,
startOffset + dataComponentOffset, dataTypeComponent.getDataType(), fieldname,
monitor);
}
return structureDataType;
}
/**
* Method to add the given structcure component to the given structure at the given offset
* @param structureDataType the structure to add to
* @param structureToAdd the structure to add
* @param startOffset the starting offset where to add
* @return the updated structure
* @throws CancelledException if cancelled
*/
public Structure addIndividualComponentsToStructure(Structure structureDataType,
Structure structureToAdd, int startOffset) throws CancelledException {
DataTypeComponent[] definedComponents = structureToAdd.getDefinedComponents();
for (int ii = 0; ii < definedComponents.length; ii++) {
monitor.checkCanceled();
DataTypeComponent dataTypeComponent = structureToAdd.getComponent(ii);
int dataComponentOffset = dataTypeComponent.getOffset();
String fieldname = dataTypeComponent.getFieldName();
structureDataType = structUtils.addDataTypeToStructure(structureDataType,
startOffset + dataComponentOffset, dataTypeComponent.getDataType(), fieldname,
@ -5342,6 +5365,113 @@ public class RecoveredClassUtils {
}
/**
* Method to retrieve the offset of the virtual parent of the given class in the given structure
* @param recoveredClass the given class
* @param structure the given structure
* @return the offset of the virtual parent of the given class in the given structure
* @throws CancelledException if cancelled
*/
public int getEndOfInternalDataOffset(RecoveredClass recoveredClass, Structure structure)
throws CancelledException {
List<Structure> virtualParentClassStructures =
getVirtualParentClassStructures(recoveredClass);
// if there are no virtual parents there will be no internal data
if (virtualParentClassStructures.size() == 0) {
return NONE;
}
DataTypeComponent[] definedComponents = structure.getDefinedComponents();
if (definedComponents.length == 0) {
return NONE;
}
List<Integer> definedOffsets = new ArrayList<Integer>();
for (DataTypeComponent dataTypeComponent : definedComponents) {
monitor.checkCanceled();
definedOffsets.add(dataTypeComponent.getOffset());
}
Collections.sort(definedOffsets);
boolean firstDefined = true;
int nextOffset = 0;
// structures that contain virtual parents have data in the middle of the structure
// between non-virtual and virtual parents
// loop to find the first defined offset after the segment of undefineds
for (Integer currentOffset : definedOffsets) {
monitor.checkCanceled();
DataTypeComponent dataTypeComponent = structure.getComponentAt(currentOffset);
if (firstDefined) {
firstDefined = false;
nextOffset = currentOffset + dataTypeComponent.getLength();
continue;
}
// if the current offset is differnet than the next offset then it is after the gap
// of undefineds and we have found the offset we need to return
if (currentOffset != nextOffset) {
return currentOffset;
}
// if the currentOffset equals what we calculated as the next offset then the
// current data is contiguous to the last data so no undefineds between them and
// can continue looking for the gap of undefines
nextOffset = currentOffset + dataTypeComponent.getLength();
}
return NONE;
}
private boolean isDataAtOffsetEquivalentToStructure(Structure outerStructure,
Structure innerStructure, int offset) {
DataTypeComponent[] innerStructComponents = innerStructure.getDefinedComponents();
for (DataTypeComponent innerComponent : innerStructComponents) {
int innerOffset = innerComponent.getOffset();
DataTypeComponent outerComponent = outerStructure.getComponentAt(offset + innerOffset);
if (outerComponent == null) {
return false;
}
if (innerComponent.getFieldName().equals("vftablePtr")) {
// if one is vftablePtr and other isn't - return false
if (!outerComponent.getFieldName().equals("vftablePtr")) {
return false;
}
// if both are vftablePtrs they should both contain the innerStructure name (ie the class name) in
// the vftablePtr data type name (either <some_class_name>_vftable_for_<innerStruct name> or <innerStruct name>_vftable *
if (outerComponent.getDataType().getDisplayName().contains(
innerStructure.getName()) &&
!innerComponent.getDataType().getDisplayName().contains(
innerStructure.getName())) {
return false;
}
continue;
}
if (!innerComponent.getDataType().equals(outerComponent.getDataType())) {
return false;
}
}
return true;
}
/**
* Method to determine if the given data type is the virtual parent class structure for the given class
* @param recoveredClass the given class
@ -5379,6 +5509,71 @@ public class RecoveredClassUtils {
}
/**
* Method to determine if the given data type is the virtual parent class structure for the given class
* @param recoveredClass the given class
* @return true if the given data type is the virtual parent class structure for the given class
* @throws CancelledException if cancelled
*/
private List<Structure> getVirtualParentClassStructures(RecoveredClass recoveredClass)
throws CancelledException {
Map<RecoveredClass, Boolean> parentToBaseTypeMap = recoveredClass.getParentToBaseTypeMap();
List<Structure> virtualParentStructures = new ArrayList<Structure>();
Set<RecoveredClass> parentClasses = parentToBaseTypeMap.keySet();
// if no parents, return empty list
if (parentClasses.isEmpty()) {
return virtualParentStructures;
}
for (RecoveredClass parentClass : parentClasses) {
monitor.checkCanceled();
Boolean isVirtualParent = parentToBaseTypeMap.get(parentClass);
if (isVirtualParent) {
Structure parentStructure = getClassStructureFromDataTypeManager(parentClass);
if (parentStructure != null) {
virtualParentStructures.add(parentStructure);
}
}
}
return virtualParentStructures;
}
/**
* Method to determine if the given data type is the virtual parent class structure for the given class
* @param recoveredClass the given class
* @return true if the given data type is the virtual parent class structure for the given class
* @throws CancelledException if cancelled
*/
protected List<RecoveredClass> getVirtualParentClasses(RecoveredClass recoveredClass)
throws CancelledException {
Map<RecoveredClass, Boolean> parentToBaseTypeMap = recoveredClass.getParentToBaseTypeMap();
List<RecoveredClass> virtualParents = new ArrayList<RecoveredClass>();
Set<RecoveredClass> parentClasses = parentToBaseTypeMap.keySet();
Iterator<RecoveredClass> parentClassIterator = parentClasses.iterator();
while (parentClassIterator.hasNext()) {
monitor.checkCanceled();
RecoveredClass parentClass = parentClassIterator.next();
Boolean isVirtualParent = parentToBaseTypeMap.get(parentClass);
if (isVirtualParent) {
virtualParents.add(parentClass);
}
}
return virtualParents;
}
/**
* Method to determine if all of a class's vftables are accounted for in its classOffsetToVftableMap
* @param recoveredClass the given class
@ -5834,6 +6029,7 @@ public class RecoveredClassUtils {
}
}
/**
* Method to retrieve the offset of the class data in the given structure
* @param recoveredClass the given class
@ -5844,15 +6040,15 @@ public class RecoveredClassUtils {
public int getDataOffset(RecoveredClass recoveredClass, Structure structure)
throws CancelledException {
int offsetOfVirtualParent = getOffsetOfVirtualParent(recoveredClass, structure);
int endOfInternalDataOffset = getEndOfInternalDataOffset(recoveredClass, structure);
int endOfData;
if (offsetOfVirtualParent == NONE) {
if (endOfInternalDataOffset == NONE) {
endOfData = structure.getLength();
}
else {
// end of data is beginning of virt parent
endOfData = offsetOfVirtualParent;
endOfData = endOfInternalDataOffset;
}
int dataLength =
@ -6982,8 +7178,7 @@ public class RecoveredClassUtils {
return componentFunctionDefinition;
}
//TODO: use the below to find the dt's I need in the other methods
//dataTypeManager.findDataTypes(name, list, caseSensitive, monitor);
private Address getVftableAddress(Structure vftableStructure) throws CancelledException {
SymbolIterator symbolIterator =
@ -7339,24 +7534,24 @@ public class RecoveredClassUtils {
return null;
}
String parentName = "";
// If the vftable structure has a _for_<parent name> use that to get the parent name (actually
// ancestor name because sometimes it is for a higher ancestor)
String vftableSuffix = getForClassSuffix(vftableStructure.getName());
if (!vftableSuffix.isEmpty()) {
parentName = getParentClassNameFromForClassSuffix(vftableSuffix);
}
else {
// parse the description to get class parent names
List<String> parentNames =
getParentNamesFromClassStructureDescription(classStructure.getDescription());
if (parentNames.isEmpty()) {
return null;
}
String parentName = new String();
if (parentNames.size() == 1) {
parentName = parentNames.get(0);
}
else {
// otherwise, use the name of the vftableStructure to get the correct parent
String vftableSuffix = getForClassSuffix(vftableStructure.getName());
String possibleParentName = getParentClassNameFromForClassSuffix(vftableSuffix);
if (parentNames.contains(possibleParentName)) {
parentName = possibleParentName;
}
// else we don't know the parent if it didn't get through either the _for<parent>
// check or the single parent check
}
if (parentName.isEmpty()) {
@ -7367,16 +7562,20 @@ public class RecoveredClassUtils {
CategoryPath parentCategoryPath = parentStructure.getCategoryPath();
// return null if no vftable in this class
List<Structure> parentVftableStructs = getVftableStructuresInClass(parentCategoryPath);
if (parentVftableStructs.size() != 1) {
// either no vftable so can't get a component or more than one and we can't determine
// which is the correct vftable
// TODO: investigate how to determine correct vftable if parent has more than one
if (parentVftableStructs.isEmpty()) {
return null;
}
if (parentVftableStructs.get(0).getNumComponents() - 1 >= component.getOrdinal()) {
return parentVftableStructs.get(0).getComponent(component.getOrdinal());
// use name of vftable struct to get correct parent struct
for (Structure parentVftableStruct : parentVftableStructs) {
if (parentVftableStruct.getName().endsWith(parentName)) {
if (parentVftableStruct.getNumComponents() - 1 >= component.getOrdinal()) {
return parentVftableStruct.getComponent(component.getOrdinal());
}
}
}
return null;
@ -7415,18 +7614,96 @@ public class RecoveredClassUtils {
return parentNames;
}
// TODO: pulled from prototype api dev branch - either update api to use the utils or utils to use the api
private Structure getParentClassStructure(Structure childClassStructure, String nameOfParent)
throws CancelledException {
// get the data type folder of the component and then see if there is
// a struct in it with parent name and return that parent struct if so
DataTypeComponent[] components = childClassStructure.getComponents();
for (DataTypeComponent component : components) {
monitor.checkCanceled();
DataType componentDataType = component.getDataType();
if (componentDataType.getName().equals(nameOfParent)) {
return (Structure) componentDataType;
CategoryPath componentPath = componentDataType.getCategoryPath();
DataType possibleParentDT = dataTypeManager.getDataType(componentPath, nameOfParent);
if (possibleParentDT != null) {
return (Structure) possibleParentDT;
}
}
// otherwise, use the dtman to find a singular match in the class data types folder
// or null if none found
return getParentStructureFromClassStructures(nameOfParent);
}
/**
* Attempts to get the parent structure from the list of class structures
* @param parentName the name of the parent
* @return the parent structure if there is only one with the given name, else returns null
* @throws CancelledException if cancelled
*/
private Structure getParentStructureFromClassStructures(String parentName)
throws CancelledException {
List<Structure> classStructures = getClassStructures();
List<Structure> parentStructures = new ArrayList<Structure>();
for (Structure classStructure : classStructures) {
monitor.checkCanceled();
if (classStructure.getName().equals(parentName)) {
parentStructures.add(classStructure);
}
}
if (parentStructures.size() == 1) {
return parentStructures.get(0);
}
return null;
}
public List<Structure> getClassStructures() throws CancelledException {
Category category = program.getDataTypeManager().getCategory(classDataTypesCategoryPath);
if (category == null) {
return null;
}
Category[] subCategories = category.getCategories();
return getClassStructures(subCategories);
}
private List<Structure> getClassStructures(Category[] categories) throws CancelledException {
List<Structure> classStructures = new ArrayList<Structure>();
for (Category category : categories) {
monitor.checkCanceled();
DataType[] dataTypes = category.getDataTypes();
for (DataType dataType : dataTypes) {
monitor.checkCanceled();
if (dataType.getName().equals(category.getName()) &&
dataType instanceof Structure) {
// if the data type name is the same as the folder name then
// it is the main class structure
Structure classStructure = (Structure) dataType;
if (!classStructures.contains(classStructure)) {
classStructures.add(classStructure);
}
}
}
Category[] subcategories = category.getCategories();
if (subcategories.length > 0) {
classStructures.addAll(getClassStructures(subcategories));
}
}
return classStructures;
}
private List<Object> updateList(List<Object> mainList, List<Object> itemsToAdd)