mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
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:
parent
513c9beb9d
commit
a8e39d58c4
2 changed files with 628 additions and 74 deletions
|
@ -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,
|
||||
classStructureDataType, dataLen, dataOffset);
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
// parse the description to get class parent names
|
||||
List<String> parentNames =
|
||||
getParentNamesFromClassStructureDescription(classStructure.getDescription());
|
||||
if (parentNames.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
String parentName = "";
|
||||
|
||||
String parentName = new String();
|
||||
if (parentNames.size() == 1) {
|
||||
parentName = parentNames.get(0);
|
||||
// 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 {
|
||||
// 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;
|
||||
// parse the description to get class parent names
|
||||
List<String> parentNames =
|
||||
getParentNamesFromClassStructureDescription(classStructure.getDescription());
|
||||
|
||||
if (parentNames.size() == 1) {
|
||||
parentName = parentNames.get(0);
|
||||
}
|
||||
// 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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue