diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionDefinitionUpdatesScript.java b/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionDefinitionUpdatesScript.java index 25b6922a49..e57b363c91 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionDefinitionUpdatesScript.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionDefinitionUpdatesScript.java @@ -27,7 +27,7 @@ import java.util.List; -import classrecovery.RecoveredClassUtils; +import classrecovery.RecoveredClassHelper; import ghidra.app.script.GhidraScript; import ghidra.program.model.data.FunctionDefinition; import ghidra.program.model.data.Structure; @@ -44,17 +44,17 @@ public class ApplyClassFunctionDefinitionUpdatesScript extends GhidraScript { return; } - RecoveredClassUtils classUtils = new RecoveredClassUtils(currentProgram, currentLocation, + RecoveredClassHelper classHelper = new RecoveredClassHelper(currentProgram, currentLocation, state.getTool(), this, false, false, false, false, monitor); - Namespace classNamespace = classUtils.getClassNamespace(currentAddress); + Namespace classNamespace = classHelper.getClassNamespace(currentAddress); if (classNamespace == null) { println( "Either cannot retrieve class namespace or cursor is not in a member of a class namepace"); return; } - List classVftableSymbols = classUtils.getClassVftableSymbols(classNamespace); + List classVftableSymbols = classHelper.getClassVftableSymbols(classNamespace); if (classVftableSymbols.isEmpty()) { println("There are no vftables in this class"); return; @@ -64,7 +64,7 @@ public class ApplyClassFunctionDefinitionUpdatesScript extends GhidraScript { "Applying differing function definitions for class " + classNamespace.getName(true)); List changedItems = - classUtils.applyNewFunctionDefinitions(classNamespace, classVftableSymbols); + classHelper.applyNewFunctionDefinitions(classNamespace, classVftableSymbols); if (changedItems.isEmpty()) { println("No differences found for class " + classNamespace.getName(true) + @@ -72,10 +72,10 @@ public class ApplyClassFunctionDefinitionUpdatesScript extends GhidraScript { return; } - List structuresOnList = classUtils.getStructuresOnList(changedItems); + List structuresOnList = classHelper.getStructuresOnList(changedItems); List functionDefinitionsOnList = - classUtils.getFunctionDefinitionsOnList(changedItems); - List functionsOnList = classUtils.getFunctionsOnList(changedItems); + classHelper.getFunctionDefinitionsOnList(changedItems); + List functionsOnList = classHelper.getFunctionsOnList(changedItems); println(); println("Updated structures:"); diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionSignatureUpdatesScript.java b/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionSignatureUpdatesScript.java index 6ce4321839..d0cf2c1102 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionSignatureUpdatesScript.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionSignatureUpdatesScript.java @@ -27,7 +27,7 @@ import java.util.List; -import classrecovery.RecoveredClassUtils; +import classrecovery.RecoveredClassHelper; import ghidra.app.script.GhidraScript; import ghidra.program.model.data.FunctionDefinition; import ghidra.program.model.data.Structure; @@ -44,17 +44,17 @@ public class ApplyClassFunctionSignatureUpdatesScript extends GhidraScript { return; } - RecoveredClassUtils classUtils = new RecoveredClassUtils(currentProgram, currentLocation, + RecoveredClassHelper classHelper = new RecoveredClassHelper(currentProgram, currentLocation, state.getTool(), this, false, false, false, false, monitor); - Namespace classNamespace = classUtils.getClassNamespace(currentAddress); + Namespace classNamespace = classHelper.getClassNamespace(currentAddress); if (classNamespace == null) { println( "Either cannot retrieve class namespace or cursor is not in a member of a class namepace"); return; } - List classVftableSymbols = classUtils.getClassVftableSymbols(classNamespace); + List classVftableSymbols = classHelper.getClassVftableSymbols(classNamespace); if (classVftableSymbols.isEmpty()) { println("There are no vftables in this class"); return; @@ -64,7 +64,7 @@ public class ApplyClassFunctionSignatureUpdatesScript extends GhidraScript { classNamespace.getName(true)); List changedItems = - classUtils.applyNewFunctionSignatures(classNamespace, classVftableSymbols); + classHelper.applyNewFunctionSignatures(classNamespace, classVftableSymbols); if (changedItems.isEmpty()) { println("No differences found for class " + classNamespace.getName(true) + @@ -72,10 +72,10 @@ public class ApplyClassFunctionSignatureUpdatesScript extends GhidraScript { return; } - List structuresOnList = classUtils.getStructuresOnList(changedItems); + List structuresOnList = classHelper.getStructuresOnList(changedItems); List functionDefinitionsOnList = - classUtils.getFunctionDefinitionsOnList(changedItems); - List functionsOnList = classUtils.getFunctionsOnList(changedItems); + classHelper.getFunctionDefinitionsOnList(changedItems); + List functionsOnList = classHelper.getFunctionsOnList(changedItems); println(); println("Updated structures:"); diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/EditStructureUtils.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/EditStructureUtils.java index 26e380621d..a1dcb64b75 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/EditStructureUtils.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/EditStructureUtils.java @@ -78,7 +78,8 @@ class EditStructureUtils { // component lengths are equal if it gets here // if containing is not undefined then return false because the components would be // incompatible types - if (!containingComDt.getName().startsWith("undefined")) { + + if (!Undefined.isUndefined(containingComDt)) { return false; } @@ -109,7 +110,7 @@ class EditStructureUtils { return false; } DataType dataType = component.getDataType(); - if (dataType.getName().equals("undefined") && dataType.getLength() == 1) { + if (dataType == DataType.DEFAULT) { continue; } return false; @@ -180,17 +181,6 @@ class EditStructureUtils { return false; } - /** - * Method to determine if data type is an undefined data type of any size - * @param dataType the given data type - * @return true if given data type is undefined of any size, false otherwise - */ - static boolean isUndefined(DataType dataType) { - if (dataType.getName().contains("undefined")) { - return true; - } - return false; - } /** * Method to determine if there are at least the given length of undefined (any size) components @@ -241,6 +231,8 @@ class EditStructureUtils { * at the given offset, don't replace. If there is undefined data there then replace * it with the data type. If the structure empty, insert the data type at the given offset. * If the structure is not big enough and not-empty, grow it so there is room to replace. + * See {@link #canAdd(Structure, int, int, TaskMonitor)} for ensuring operation will be + * successful. * @param structure the given structure * @param offset the offset to add a field * @param dataType the data type to add to the field at the given offset @@ -253,76 +245,74 @@ class EditStructureUtils { static Structure addDataTypeToStructure(Structure structure, int offset, DataType dataType, String fieldName, TaskMonitor monitor) throws CancelledException, IllegalArgumentException { - - int dataTypeLength = dataType.getLength(); - - int endOfDataTypeInStruct = offset + dataTypeLength; - - int roomForData = structure.getLength() - endOfDataTypeInStruct; - // FIXME: This will not worked for structures where packing is enabled - not sure how to handle - - // if structure isn't defined insert - if (structure.isNotYetDefined()) { - structure.insertAtOffset(offset, dataType, dataTypeLength, fieldName, null); - return structure; + if (structure.isPackingEnabled()) { + throw new IllegalArgumentException( + "Packed structures are not supported by this method"); } - // if not enough room, grow the structure - if (roomForData < 0) { - structure.growStructure(0 - roomForData); + if (structure.isZeroLength() || offset >= structure.getLength()) { + structure.insertAtOffset(offset, dataType, -1, fieldName, null); } - - // else replace only if data already there are enough undefined data types at - // that offset to fit the new data type - if (hasEnoughUndefined1sAtOffset(structure, offset, dataTypeLength, monitor)) { - structure.replaceAtOffset(offset, dataType, dataTypeLength, fieldName, null); + else { + structure.replaceAtOffset(offset, dataType, -1, fieldName, null); } - return structure; } /** - * Method to determine if the given structure has room at the given offset to have a component of the given length added to it + * Method to determine if the given structure has room at the given offset to have a component + * of the given length added to it. This is only valid for non-packed structures. * @param structureDataType the given structure * @param offset the offset to check for available room * @param lengthToAdd the length of bytes wanted to add at the offset * @param monitor task monitor - * @return true if the given structure has room at the given offset to have a component of the given length added to it + * @return true if the given structure has room at the given offset to have a component of the + * given length added to it or if the offset is beyond the end of the structure so that the + * structure can be grown * @throws CancelledException if cancelled + * @throws IllegalArgumentException if a packed structure is passed in */ static boolean canAdd(Structure structureDataType, int offset, int lengthToAdd, - TaskMonitor monitor) - throws CancelledException { + TaskMonitor monitor) throws CancelledException { - // not big enough so return true so it can be grown - DataTypeComponent component = structureDataType.getComponentAt(offset); + if (structureDataType.isPackingEnabled()) { + throw new IllegalArgumentException( + "Packed structures are not supported by this method"); + } + + DataTypeComponent component = structureDataType.getComponentContaining(offset); + + // structure not big enough to contain the offset so return true so it can be grown if (component == null) { return true; } - // no matter what size, if the data type at the offset is defined, return false - // so it is not replaced - if (!component.getDataType().getName().equals("undefined")) { + // if the offset is in the middle of an internal component then return false + if (component.getOffset() != offset) { return false; } - // if structure isn't big enough but what is there is all undefined - // return true to grow it - int structLen = structureDataType.getLength(); - int spaceAvailable = structLen - (offset + lengthToAdd); - - if (spaceAvailable < 0) { - int overflow = 0 - spaceAvailable; - return hasEnoughUndefined1sAtOffset(structureDataType, offset, structLen - overflow, - monitor); + // no matter what size, if the data type at the offset is defined, return false + // so it is not replaced + if (component.getDataType() != DataType.DEFAULT) { + return false; } - // if structure is big enough and there is room at the offset return true - return hasEnoughUndefined1sAtOffset(structureDataType, offset, lengthToAdd, monitor); + if (lengthToAdd > 1) { + DataTypeComponent nextDefinedComponent = + structureDataType.getDefinedComponentAtOrAfterOffset(offset + 1); + if (nextDefinedComponent == null) { + return true; + } + int available = nextDefinedComponent.getOffset() - offset; + return available >= lengthToAdd; + } + return true; } + /** * Method to retrieve the number of undefined size 1 components in the given structure before the given offset * @param structure the given structure @@ -372,8 +362,7 @@ class EditStructureUtils { while (index < structure.getLength()) { monitor.checkCanceled(); DataTypeComponent component = structure.getComponentAt(index); - if (component.getDataType().getName().equals("undefined") && - component.getLength() == 1) { + if (component.getDataType() == DataType.DEFAULT) { index++; numUndefineds++; } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIClassRecoverer.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIClassRecoverer.java index 6b4c6f963f..62c29064c1 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIClassRecoverer.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIClassRecoverer.java @@ -31,7 +31,7 @@ import ghidra.util.Msg; import ghidra.util.exception.*; import ghidra.util.task.TaskMonitor; -public class RTTIClassRecoverer extends RecoveredClassUtils { +public class RTTIClassRecoverer extends RecoveredClassHelper { boolean programHasRTTIApplied = false; diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java index b9405909ab..2c419fda54 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java @@ -2938,6 +2938,15 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } + //NEW: + classStructureDataType = + addClassVftables(classStructureDataType, recoveredClass, vfPointerDataTypes); + + //NEW: unused at this point until something figures out how to create them and where to + // put them + classStructureDataType = + addVbtableToClassStructure(recoveredClass, classStructureDataType, true); + if (classStructureDataType.getNumComponents() == classStructureDataType .getNumDefinedComponents()) { classStructureDataType.setPackingEnabled(true); diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java index 7644501cff..2f924d4427 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java @@ -2278,7 +2278,10 @@ 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.replaceWith(classStructure); + + classStructureDataType = (Structure) dataTypeManager.addDataType(classStructureDataType, + DataTypeConflictHandler.DEFAULT_HANDLER); return classStructureDataType; } @@ -2485,183 +2488,14 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { return classStructureDataType; } - - - - private Structure addClassVftables(Structure classStructureDataType, - RecoveredClass recoveredClass, Map 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 classOffsetToVftableMap = recoveredClass.getClassOffsetToVftableMap(); - Set 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 (EditStructureUtils.canAdd(classStructureDataType, vftableOffset, - classVftablePointer.getLength(), monitor)) { - - classStructureDataType = - EditStructureUtils.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 = - EditStructureUtils.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 - * @throws AddressOutOfBoundsException - * @throws MemoryAccessException + * @throws AddressOutOfBoundsException if trying to access an address that does not exist in program + * @throws MemoryAccessException if trying to access memory that can't be accessed */ public Integer getSingleVirtualParentOffset(RecoveredClass recoveredClass) throws CancelledException, MemoryAccessException, AddressOutOfBoundsException { @@ -2782,41 +2616,6 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { return baseClass; } - /** - * Method to add a pointer to the class vbtable to the given class's class structure - * @param recoveredClass the given class - * @param classStructureDataType the given class's class structure data type - * @return the updated class structure - * @throws CancelledException if cancelled - */ - private Structure addVbtableToClassStructure(RecoveredClass recoveredClass, - Structure classStructureDataType, boolean overwrite) throws CancelledException { - - Structure vbtableStructure = recoveredClass.getVbtableStructure(); - - if (vbtableStructure != null) { - - int vbtableOffset = recoveredClass.getVbtableOffset(); - - DataType vbaseStructPointer = dataTypeManager.getPointer(vbtableStructure); - - int dataLength = vbaseStructPointer.getLength(); - if (EditStructureUtils.canAdd(classStructureDataType, vbtableOffset, dataLength, - monitor)) { - - classStructureDataType = - EditStructureUtils.addDataTypeToStructure(classStructureDataType, - vbtableOffset, vbaseStructPointer, "vbtablePtr", monitor); - - } - else if (overwrite) { - classStructureDataType.replaceAtOffset(vbtableOffset, vbaseStructPointer, - vbaseStructPointer.getLength(), "vbtablePtr", ""); - } - } - return classStructureDataType; - } - /** * Method to apply the given class's vbtable structure * @param recoveredClass the given RecoveredClass object which, if applicable, contains the address and structure to apply diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassUtils.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java similarity index 97% rename from Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassUtils.java rename to Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java index d69c960e48..8c47f4986d 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassUtils.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java @@ -47,17 +47,19 @@ import ghidra.util.datastruct.ListAccumulator; import ghidra.util.exception.*; import ghidra.util.task.TaskMonitor; -public class RecoveredClassUtils { +public class RecoveredClassHelper { public static final String DTM_CLASS_DATA_FOLDER_NAME = "ClassDataTypes"; private static final String CLASS_DATA_STRUCT_NAME = "_data"; private static final String DEFAULT_VFUNCTION_PREFIX = "vfunction"; private static final String VFUNCTION_COMMENT = "virtual function #"; private static final String CLASS_VFUNCTION_STRUCT_NAME = "_vftable"; + private static final String CLASS_VTABLE_PTR_FIELD_EXT = "vftablePtr"; public static final String VFTABLE_LABEL = "vftable"; private static final String VBASE_DESTRUCTOR_LABEL = "vbase_destructor"; private static final String VBTABLE_LABEL = "vbtable"; + private static final String VBTABLE_PTR = "vbtablePtr"; private static final String CLONE_LABEL = "clone"; private static final String DELETING_DESTRUCTOR_LABEL = "deleting_destructor"; @@ -145,7 +147,7 @@ public class RecoveredClassUtils { boolean nameVfunctions; boolean replaceClassStructures; - public RecoveredClassUtils(Program program, ProgramLocation location, PluginTool tool, + public RecoveredClassHelper(Program program, ProgramLocation location, PluginTool tool, FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates, boolean nameVunctions, boolean replaceClassStructures, TaskMonitor monitor) throws Exception { @@ -3521,7 +3523,6 @@ public class RecoveredClassUtils { } /** -<<<<<<< HEAD * Method to replace the program's current class structure, only if an empty placeholder structure, * with the one generated by this script * @param function a class method with current class structure applied @@ -5520,34 +5521,6 @@ public class RecoveredClassUtils { 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 = EditStructureUtils.addDataTypeToStructure(structureDataType, - startOffset + dataComponentOffset, dataTypeComponent.getDataType(), fieldname, - monitor); - } - return structureDataType; - } /** * Method to add alignment to the given length based on the default program address size @@ -7000,7 +6973,7 @@ public class RecoveredClassUtils { } DataType dataType = definedComponent.getDataType(); - if (dataType.getName().equals("undefined") && dataType.getLength() == 1) { + if (dataType == DataType.DEFAULT) { dataType = new Undefined1DataType(); } @@ -7030,30 +7003,6 @@ public class RecoveredClassUtils { return classDataStructure; } - /** - * Method to use the computed or existing class structure contents for the main class structure. - * This is called when there is not enough information to create a full structure. - * @param computedClassStructure the structure computed using pcode store information or using pdb information - * @param classStructureDataType the structure that is getting created in the data type manager - * @return the default class structure for this class - * @throws CancelledException if cancelled - */ - public Structure createDefaultStructure(Structure computedClassStructure, - Structure classStructureDataType) throws CancelledException { - - DataTypeComponent[] definedComponents = computedClassStructure.getDefinedComponents(); - for (DataTypeComponent component : definedComponents) { - monitor.checkCanceled(); - - classStructureDataType = EditStructureUtils.addDataTypeToStructure( - classStructureDataType, component.getOffset(), component.getDataType(), - component.getFieldName(), monitor); - } - classStructureDataType = (Structure) dataTypeManager.addDataType(classStructureDataType, - DataTypeConflictHandler.DEFAULT_HANDLER); - - return classStructureDataType; - } /** * Method to find the purecall function. @@ -8204,4 +8153,166 @@ public class RecoveredClassUtils { return category; } + /** + * Method to add class vftable pointers to the given class structure + * @param classStructureDataType the class structure data type + * @param recoveredClass the given recovered class + * @param vfPointerDataTypes the map of addresses/vftables, a null should be passed to indicate + * no known vftables for the given class. + * @return the modified structure with the vftable pointers added or an unchanged structure if + * the vftable map is null or if the given class's offset to vftable map is empty + * @throws CancelledException if cancelled + * @throws IllegalArgumentException if there are issues modifying the structure + */ + protected Structure addClassVftables(Structure classStructureDataType, + RecoveredClass recoveredClass, Map vfPointerDataTypes) + throws CancelledException, IllegalArgumentException { + + Map classOffsetToVftableMap = recoveredClass.getClassOffsetToVftableMap(); + Set classVftableOffsets = classOffsetToVftableMap.keySet(); + + if (vfPointerDataTypes == null || classVftableOffsets.isEmpty()) { + return classStructureDataType; + } + + // If the map is not empty, the class structure will contain incomplete information so + // put out a debug message to indicate this issue + if (!isClassOffsetToVftableMapComplete(recoveredClass)) { + Msg.debug(this, + "class vftable offset map for " + recoveredClass.getName() + " is not complete"); + } + + // iterate over the set of offsets to vftables and either add to undefined area or overwrite + // the parent class structures with the class vftable pointer then replace the rest of the + // parent structure with its internal components + for (Integer offset : classVftableOffsets) { + monitor.checkCanceled(); + + Address vftableAddress = classOffsetToVftableMap.get(offset); + + int vftableOffset = offset.intValue(); + + DataType classVftablePointer = vfPointerDataTypes.get(vftableAddress); + + boolean addedVftablePointer = false; + + // loop until the vftable pointer is added + // if component at offset is not a structure, replace with vftablePtr + // if component at offset is a structure, replace with components then loop + // until finally component is not a structure and can be replaced + while (!addedVftablePointer) { + + monitor.checkCanceled(); + + // if enough empty bytes - add class vftable pointer + if (EditStructureUtils.canAdd(classStructureDataType, vftableOffset, + classVftablePointer.getLength(), monitor)) { + + classStructureDataType = + EditStructureUtils.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 + //NEW: replaced with get containing + // if offset is in the middle, get the top of the component + DataTypeComponent currentComponent = + classStructureDataType.getComponentContaining(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; + } + + // if the current component isn't a structure just replace it with the + // vftable pointer + if (!(currentComponent.getDataType() instanceof Structure)) { + classStructureDataType.replaceAtOffset(vftableOffset, classVftablePointer, + classVftablePointer.getLength(), CLASS_VTABLE_PTR_FIELD_EXT, ""); + addedVftablePointer = true; + continue; + } + + // if there is a structure at the offset, replace it with its pieces then + // loop again to try to place vftable pointer over either empty bytes or + // base vftableptr + DataType currentDT = currentComponent.getDataType(); + Structure internalStruct = (Structure) currentDT; + + DataTypeComponent[] components = internalStruct.getComponents(); + + // if there is an empty structure at the offset, clear it which will replace + // it with an undefined data type of size 1 + if (components.length == 0) { + classStructureDataType.clearAtOffset(componentOffset); + continue; + } + // if non-empty, replace the structure with its components + 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; + } + + /** + * Method to add a pointer to the class vbtable to the given class's class structure + * @param recoveredClass the given class + * @param classStructureDataType the given class's class structure data type + * @param overwrite if true, overwrite existing item with the vbtable pointer, if false, don't + * @return the updated class structure + * @throws CancelledException if cancelled + */ + protected Structure addVbtableToClassStructure(RecoveredClass recoveredClass, + Structure classStructureDataType, boolean overwrite) throws CancelledException { + + Structure vbtableStructure = recoveredClass.getVbtableStructure(); + + if (vbtableStructure != null) { + + int vbtableOffset = recoveredClass.getVbtableOffset(); + + DataType vbaseStructPointer = dataTypeManager.getPointer(vbtableStructure); + + int dataLength = vbaseStructPointer.getLength(); + if (EditStructureUtils.canAdd(classStructureDataType, vbtableOffset, dataLength, + monitor)) { + + classStructureDataType = + EditStructureUtils.addDataTypeToStructure(classStructureDataType, + vbtableOffset, vbaseStructPointer, VBTABLE_PTR, monitor); + + } + else if (overwrite) { + classStructureDataType.replaceAtOffset(vbtableOffset, vbaseStructPointer, + vbaseStructPointer.getLength(), VBTABLE_PTR, ""); + } + } + return classStructureDataType; + } + }