diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/EditStructureUtils.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/EditStructureUtils.java index a1dcb64b75..45e1936775 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/EditStructureUtils.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/EditStructureUtils.java @@ -226,55 +226,68 @@ class EditStructureUtils { return true; } + /** * Method to add a field to the given structure. If the structure already has data * 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 + * See {@link #canAdd(Structure, int, int, boolean, 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 * @param fieldName the name of field * @param monitor task monitor - * @return the updated structure data type - * @throws IllegalArgumentException if issue inserting data type into structure + * @return true if the structure was updated or false if the data could not be added + * @throws IllegalArgumentException if issue inserting or replacing data type into structure * @throws CancelledException if cancelled */ - static Structure addDataTypeToStructure(Structure structure, int offset, - DataType dataType, String fieldName, TaskMonitor monitor) - throws CancelledException, IllegalArgumentException { - + static boolean addDataTypeToStructure(Structure structure, int offset, DataType dataType, + String fieldName, TaskMonitor monitor) throws CancelledException { + if (structure.isPackingEnabled()) { throw new IllegalArgumentException( "Packed structures are not supported by this method"); } + if (!canAdd(structure, offset, dataType.getLength(), true, monitor)) { + return false; + } + if (structure.isZeroLength() || offset >= structure.getLength()) { structure.insertAtOffset(offset, dataType, -1, fieldName, null); } else { + // if not enough room, grow the structure + int roomForData = structure.getLength() - (offset + dataType.getLength()); + if (roomForData < 0) { + structure.growStructure(-roomForData); + } structure.replaceAtOffset(offset, dataType, -1, fieldName, null); } - return structure; + return true; } + /** * 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 isGrowthAllowed Whether true or false, adding is only allowed if no collision will + * happen with existing defined components. If true, allows structure to be grown beyond its end + * if necessary. If false, it does not allow structure to be grown. * @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 or if the offset is beyond the end of the structure so that the - * structure can be grown + * given length added to it or if the offset is beyond the end of the defined components in the + * 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 { + boolean isGrowthAllowed, TaskMonitor monitor) throws CancelledException { if (structureDataType.isPackingEnabled()) { throw new IllegalArgumentException( @@ -283,12 +296,24 @@ class EditStructureUtils { DataTypeComponent component = structureDataType.getComponentContaining(offset); - // structure not big enough to contain the offset so return true so it can be grown + // structure not big enough to contain the offset + // if growStructure flag is true, return true so structure can be grown + // if growStructure flag is false, return false since the offset does not exist so it would + // be impossible to add anything at that offset if (component == null) { - return true; + if (isGrowthAllowed) { + return true; + } + return false; } - // if the offset is in the middle of an internal component then return false + // if growStructure flag is false and if offset + lengthToAdd is greater than length of + // structure then return false + if (!isGrowthAllowed && (structureDataType.getLength() < (offset + lengthToAdd))) { + return false; + } + + // if the offset is in the middle of an internal component then return false if (component.getOffset() != offset) { return false; } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java index 6f02ec70d0..412dde27c5 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java @@ -2906,13 +2906,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { DataType classVftablePointer = vfPointerDataTypes.get(vftableAddress); // simple case the offset for vftablePtr is 0 - if (EditStructureUtils.canAdd(classStructureDataType, 0, - classVftablePointer.getLength(), monitor)) { - classStructureDataType = - EditStructureUtils.addDataTypeToStructure(classStructureDataType, 0, - classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor); - - } + // if can fit or grow structure, add the vftablePtr to it + EditStructureUtils.addDataTypeToStructure(classStructureDataType, 0, + classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor); } // if single inheritance or multi non-virtual (wouldn't have called this method if // it were virtually inherited) put parent struct and data into class struct @@ -2953,12 +2949,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { " : structure should exist but doesn't."); } - if (EditStructureUtils.canAdd(classStructureDataType, parentOffset, - baseClassStructure.getLength(), monitor)) { - classStructureDataType = EditStructureUtils.addDataTypeToStructure( - classStructureDataType, parentOffset, baseClassStructure, - baseClassStructure.getName(), monitor); - } + // if it fits at offset or is at the end and class structure can be grown, + // copy the whole baseClass structure to the class Structure at the given offset + EditStructureUtils.addDataTypeToStructure(classStructureDataType, parentOffset, + baseClassStructure, baseClassStructure.getName(), monitor); } } @@ -2977,8 +2971,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { classStructureDataType, dataLen, dataOffset); if (recoveredClassDataStruct != null) { - classStructureDataType = EditStructureUtils.addDataTypeToStructure( - classStructureDataType, dataOffset, recoveredClassDataStruct, "data", monitor); + // if it fits at offset or is at the end and class structure can be grown, + // copy the whole baseClass structure to the class Structure at the given offset + EditStructureUtils.addDataTypeToStructure(classStructureDataType, dataOffset, + recoveredClassDataStruct, "data", monitor); } } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java index 2f924d4427..deae839cb6 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java @@ -1212,7 +1212,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { /** * Method to get class inheritance flag from the RTTIClassHierarchyDescriptor structure * @param classNamespace the given class namespace - * @return the class inheritance flag + * @return the class inheritance flag or NONE if there isn't one * @throws CancelledException if cancelled * @throws MemoryAccessException if memory cannot be read * @throws AddressOutOfBoundsException if try reading memory out of bounds @@ -1432,7 +1432,6 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { recoveredClass.addParentToBaseTypeMapping(baseClass, false); } else { - if (vbaseOffset == NONE) { vbaseOffset = pdisp; } @@ -2247,7 +2246,6 @@ 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
vfPointerDataTypes) throws Exception { @@ -2353,38 +2351,29 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { recoveredClass.getVftableAddresses().size() > 1 && recoveredClass.inheritsVirtualAncestor()) { - //NEW - int offsetOfVirtualParent = getSingleVirtualParentOffset(baseClass); + int virtParentOffset = getSingleVirtualParentOffset(baseClass); int dataLength; - if (offsetOfVirtualParent == NONE) { + if (virtParentOffset == NONE) { dataLength = baseClassStructure.getLength(); } else { - int lengthOfVirtualParent = - baseClassStructure.getLength() - offsetOfVirtualParent; - dataLength = baseClassStructure.getLength() - lengthOfVirtualParent; + int virtParentLength = baseClassStructure.getLength() - virtParentOffset; + dataLength = baseClassStructure.getLength() - virtParentLength; } - if (EditStructureUtils.canAdd(classStructureDataType, baseClassOffset, - dataLength, - monitor)) { - classStructureDataType = - addIndividualComponentsToStructure(classStructureDataType, - baseClassStructure, baseClassOffset, offsetOfVirtualParent); - } + // if there is room add the individual parts of the base class from the top of the + // structure up to but not including the single virtual parent offset within + // the class structure + addIndividualComponentsToStructure(classStructureDataType, baseClassStructure, + baseClassOffset, dataLength); continue; } - // else copy whole baseClass structure to the class Structure - if (EditStructureUtils.canAdd(classStructureDataType, baseClassOffset, - baseClassStructure.getLength(), monitor)) { - classStructureDataType = - EditStructureUtils.addDataTypeToStructure(classStructureDataType, - baseClassOffset, - baseClassStructure, baseClassStructure.getName(), monitor); - - } + // if it fits at offset or is at the end and class structure can be grown, + // copy the whole baseClass structure to the class Structure at the given offset + EditStructureUtils.addDataTypeToStructure(classStructureDataType, baseClassOffset, + baseClassStructure, baseClassStructure.getName(), monitor); } else { @@ -2397,15 +2386,11 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { baseClassOffset = api.getInt(recoveredClass.getVbtableAddress().add(vdisp)) + pdisp; - if (EditStructureUtils.canAdd(classStructureDataType, baseClassOffset, - baseClassStructure.getLength(), monitor)) { + // if it fits at offset or is at the end and class structure can be grown, + // copy the whole baseClass structure to the class Structure at the given offset + EditStructureUtils.addDataTypeToStructure(classStructureDataType, + baseClassOffset, baseClassStructure, baseClassStructure.getName(), monitor); - classStructureDataType = - EditStructureUtils.addDataTypeToStructure(classStructureDataType, - baseClassOffset, - baseClassStructure, baseClassStructure.getName(), monitor); - - } } }// end of base class array @@ -2430,13 +2415,10 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { DataType classVftablePointer = vfPointerDataTypes.get(vftableAddress); - if (EditStructureUtils.canAdd(classStructureDataType, offset.intValue(), - classVftablePointer.getLength(), monitor)) { - classStructureDataType = EditStructureUtils.addDataTypeToStructure( - classStructureDataType, - offset.intValue(), classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor); - - } + // if it fits at offset or is at the end and class structure can be grown, + // copy the whole baseClass structure to the class Structure at the given offset + EditStructureUtils.addDataTypeToStructure(classStructureDataType, + offset.intValue(), classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor); } // add the vbtable structure for single inheritance/virt parent case @@ -2445,13 +2427,11 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { addVbtableToClassStructure(recoveredClass, classStructureDataType, false); } - //NEW int dataOffset = getDataOffset(recoveredClass, classStructureDataType); int dataLen = UNKNOWN; if (dataOffset != NONE) { - dataLen = - EditStructureUtils.getNumberOfUndefinedsStartingAtOffset(classStructureDataType, - dataOffset, monitor); + dataLen = EditStructureUtils.getNumberOfUndefinedsStartingAtOffset( + classStructureDataType, dataOffset, monitor); } if (dataLen != UNKNOWN && dataLen > 0) { @@ -2460,23 +2440,22 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { classStructureDataType, dataLen, dataOffset); if (recoveredClassDataStruct != null) { - classStructureDataType = - EditStructureUtils.addDataTypeToStructure(classStructureDataType, - dataOffset, recoveredClassDataStruct, - classStructureDataType.getName() + "_data", monitor); + // if it fits at offset or is at the end and class structure can be grown, + // copy the whole baseClass structure to the class Structure at the given offset + EditStructureUtils.addDataTypeToStructure(classStructureDataType, dataOffset, + recoveredClassDataStruct, classStructureDataType.getName() + "_data", monitor); } } - //NEW: classStructureDataType = addClassVftables(classStructureDataType, recoveredClass, vfPointerDataTypes); - //NEW: classStructureDataType = addVbtableToClassStructure(recoveredClass, classStructureDataType, true); - if (classStructureDataType.getNumComponents() == classStructureDataType.getNumDefinedComponents()) { + if (classStructureDataType.getNumComponents() == classStructureDataType + .getNumDefinedComponents()) { classStructureDataType.setPackingEnabled(true); } @@ -2491,8 +2470,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { /** * 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 + * @return the offset in the given class structure of the classes single virtual parent or NONE + * if cannot retrieve an offset value or if there is not a single virtual parent for the given + * class. * @throws CancelledException if cancelled * @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 @@ -2502,7 +2482,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { List