GP-1670 Fixed bug in a class recovery helper class that in some cases was causing an exception when trying to replace a component in a structure.

This commit is contained in:
ghidra007 2022-01-24 21:34:12 +00:00
parent 8546ff5274
commit 87d6ff4db3
4 changed files with 122 additions and 131 deletions

View file

@ -226,55 +226,68 @@ class EditStructureUtils {
return true; return true;
} }
/** /**
* Method to add a field to the given structure. If the structure already has data * 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 * 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. * 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. * 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. * successful.
* @param structure the given structure * @param structure the given structure
* @param offset the offset to add a field * @param offset the offset to add a field
* @param dataType the data type to add to the field at the given offset * @param dataType the data type to add to the field at the given offset
* @param fieldName the name of field * @param fieldName the name of field
* @param monitor task monitor * @param monitor task monitor
* @return the updated structure data type * @return true if the structure was updated or false if the data could not be added
* @throws IllegalArgumentException if issue inserting data type into structure * @throws IllegalArgumentException if issue inserting or replacing data type into structure
* @throws CancelledException if cancelled * @throws CancelledException if cancelled
*/ */
static Structure addDataTypeToStructure(Structure structure, int offset, static boolean addDataTypeToStructure(Structure structure, int offset, DataType dataType,
DataType dataType, String fieldName, TaskMonitor monitor) String fieldName, TaskMonitor monitor) throws CancelledException {
throws CancelledException, IllegalArgumentException {
if (structure.isPackingEnabled()) { if (structure.isPackingEnabled()) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Packed structures are not supported by this method"); "Packed structures are not supported by this method");
} }
if (!canAdd(structure, offset, dataType.getLength(), true, monitor)) {
return false;
}
if (structure.isZeroLength() || offset >= structure.getLength()) { if (structure.isZeroLength() || offset >= structure.getLength()) {
structure.insertAtOffset(offset, dataType, -1, fieldName, null); structure.insertAtOffset(offset, dataType, -1, fieldName, null);
} }
else { 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); 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 * 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. * of the given length added to it. This is only valid for non-packed structures.
* @param structureDataType the given structure * @param structureDataType the given structure
* @param offset the offset to check for available room * @param offset the offset to check for available room
* @param lengthToAdd the length of bytes wanted to add at the offset * @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 * @param monitor task monitor
* @return true if the given structure has room at the given offset to have a component of the * @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 * given length added to it or if the offset is beyond the end of the defined components in the
* structure can be grown * the structure so that the structure can be grown
* @throws CancelledException if cancelled * @throws CancelledException if cancelled
* @throws IllegalArgumentException if a packed structure is passed in * @throws IllegalArgumentException if a packed structure is passed in
*/ */
static boolean canAdd(Structure structureDataType, int offset, int lengthToAdd, static boolean canAdd(Structure structureDataType, int offset, int lengthToAdd,
TaskMonitor monitor) throws CancelledException { boolean isGrowthAllowed, TaskMonitor monitor) throws CancelledException {
if (structureDataType.isPackingEnabled()) { if (structureDataType.isPackingEnabled()) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
@ -283,10 +296,22 @@ class EditStructureUtils {
DataTypeComponent component = structureDataType.getComponentContaining(offset); 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) { if (component == null) {
if (isGrowthAllowed) {
return true; return true;
} }
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 the offset is in the middle of an internal component then return false
if (component.getOffset() != offset) { if (component.getOffset() != offset) {

View file

@ -2857,14 +2857,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
DataType classVftablePointer = vfPointerDataTypes.get(vftableAddress); DataType classVftablePointer = vfPointerDataTypes.get(vftableAddress);
// simple case the offset for vftablePtr is 0 // simple case the offset for vftablePtr is 0
if (EditStructureUtils.canAdd(classStructureDataType, 0, // if can fit or grow structure, add the vftablePtr to it
classVftablePointer.getLength(), EditStructureUtils.addDataTypeToStructure(classStructureDataType, 0,
monitor)) { classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor);
classStructureDataType =
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 // 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 // it were virtually inherited) put parent struct and data into class struct
@ -2905,14 +2900,11 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
" : structure should exist but doesn't."); " : structure should exist but doesn't.");
} }
if (EditStructureUtils.canAdd(classStructureDataType, parentOffset, // if it fits at offset or is at the end and class structure can be grown,
baseClassStructure.getLength(), monitor)) { // copy the whole baseClass structure to the class Structure at the given offset
classStructureDataType = EditStructureUtils.addDataTypeToStructure(classStructureDataType, parentOffset,
EditStructureUtils.addDataTypeToStructure(classStructureDataType,
parentOffset,
baseClassStructure, baseClassStructure.getName(), monitor); baseClassStructure, baseClassStructure.getName(), monitor);
} }
}
} }
@ -2920,9 +2912,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
int dataOffset = getDataOffset(recoveredClass, classStructureDataType); int dataOffset = getDataOffset(recoveredClass, classStructureDataType);
int dataLen = UNKNOWN; int dataLen = UNKNOWN;
if (dataOffset != NONE) { if (dataOffset != NONE) {
dataLen = dataLen = EditStructureUtils.getNumberOfUndefinedsStartingAtOffset(
EditStructureUtils.getNumberOfUndefinedsStartingAtOffset(classStructureDataType, classStructureDataType, dataOffset, monitor);
dataOffset, monitor);
} }
if (dataLen != UNKNOWN && dataLen > 0) { if (dataLen != UNKNOWN && dataLen > 0) {
@ -2931,9 +2922,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
classStructureDataType, dataLen, dataOffset); classStructureDataType, dataLen, dataOffset);
if (recoveredClassDataStruct != null) { if (recoveredClassDataStruct != null) {
classStructureDataType = EditStructureUtils.addDataTypeToStructure( // if it fits at offset or is at the end and class structure can be grown,
classStructureDataType, // copy the whole baseClass structure to the class Structure at the given offset
dataOffset, recoveredClassDataStruct, "data", monitor); EditStructureUtils.addDataTypeToStructure(classStructureDataType, dataOffset,
recoveredClassDataStruct, "data", monitor);
} }
} }

View file

@ -1212,7 +1212,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
/** /**
* Method to get class inheritance flag from the RTTIClassHierarchyDescriptor structure * Method to get class inheritance flag from the RTTIClassHierarchyDescriptor structure
* @param classNamespace the given class namespace * @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 CancelledException if cancelled
* @throws MemoryAccessException if memory cannot be read * @throws MemoryAccessException if memory cannot be read
* @throws AddressOutOfBoundsException if try reading memory out of bounds * @throws AddressOutOfBoundsException if try reading memory out of bounds
@ -1432,7 +1432,6 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
recoveredClass.addParentToBaseTypeMapping(baseClass, false); recoveredClass.addParentToBaseTypeMapping(baseClass, false);
} }
else { else {
if (vbaseOffset == NONE) { if (vbaseOffset == NONE) {
vbaseOffset = pdisp; vbaseOffset = pdisp;
} }
@ -2247,7 +2246,6 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
* @return the created class structure data type * @return the created class structure data type
* @throws Exception if invalid data creation * @throws Exception if invalid data creation
*/ */
//NEW
private Structure createClassStructureUsingRTTI(RecoveredClass recoveredClass, private Structure createClassStructureUsingRTTI(RecoveredClass recoveredClass,
Map<Address, DataType> vfPointerDataTypes) throws Exception { Map<Address, DataType> vfPointerDataTypes) throws Exception {
@ -2353,40 +2351,31 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
recoveredClass.getVftableAddresses().size() > 1 && recoveredClass.getVftableAddresses().size() > 1 &&
recoveredClass.inheritsVirtualAncestor()) { recoveredClass.inheritsVirtualAncestor()) {
//NEW int virtParentOffset = getSingleVirtualParentOffset(baseClass);
int offsetOfVirtualParent = getSingleVirtualParentOffset(baseClass);
int dataLength; int dataLength;
if (offsetOfVirtualParent == NONE) { if (virtParentOffset == NONE) {
dataLength = baseClassStructure.getLength(); dataLength = baseClassStructure.getLength();
} }
else { else {
int lengthOfVirtualParent = int virtParentLength = baseClassStructure.getLength() - virtParentOffset;
baseClassStructure.getLength() - offsetOfVirtualParent; dataLength = baseClassStructure.getLength() - virtParentLength;
dataLength = baseClassStructure.getLength() - lengthOfVirtualParent;
} }
if (EditStructureUtils.canAdd(classStructureDataType, baseClassOffset, // if there is room add the individual parts of the base class from the top of the
dataLength, // structure up to but not including the single virtual parent offset within
monitor)) { // the class structure
classStructureDataType = addIndividualComponentsToStructure(classStructureDataType, baseClassStructure,
addIndividualComponentsToStructure(classStructureDataType, baseClassOffset, dataLength);
baseClassStructure, baseClassOffset, offsetOfVirtualParent);
}
continue; continue;
} }
// else copy whole baseClass structure to the class Structure // if it fits at offset or is at the end and class structure can be grown,
if (EditStructureUtils.canAdd(classStructureDataType, baseClassOffset, // copy the whole baseClass structure to the class Structure at the given offset
baseClassStructure.getLength(), monitor)) { EditStructureUtils.addDataTypeToStructure(classStructureDataType, baseClassOffset,
classStructureDataType =
EditStructureUtils.addDataTypeToStructure(classStructureDataType,
baseClassOffset,
baseClassStructure, baseClassStructure.getName(), monitor); baseClassStructure, baseClassStructure.getName(), monitor);
} }
}
else { else {
// else need to fill in the virtually inherited ones // else need to fill in the virtually inherited ones
// get the offset of this base class in the class using the vbtable // get the offset of this base class in the class using the vbtable
@ -2397,16 +2386,12 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
baseClassOffset = api.getInt(recoveredClass.getVbtableAddress().add(vdisp)) + pdisp; baseClassOffset = api.getInt(recoveredClass.getVbtableAddress().add(vdisp)) + pdisp;
if (EditStructureUtils.canAdd(classStructureDataType, baseClassOffset, // if it fits at offset or is at the end and class structure can be grown,
baseClassStructure.getLength(), monitor)) { // copy the whole baseClass structure to the class Structure at the given offset
classStructureDataType =
EditStructureUtils.addDataTypeToStructure(classStructureDataType, EditStructureUtils.addDataTypeToStructure(classStructureDataType,
baseClassOffset, baseClassOffset, baseClassStructure, baseClassStructure.getName(), monitor);
baseClassStructure, baseClassStructure.getName(), monitor);
} }
}
}// end of base class array }// end of base class array
@ -2430,13 +2415,10 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
DataType classVftablePointer = vfPointerDataTypes.get(vftableAddress); DataType classVftablePointer = vfPointerDataTypes.get(vftableAddress);
if (EditStructureUtils.canAdd(classStructureDataType, offset.intValue(), // if it fits at offset or is at the end and class structure can be grown,
classVftablePointer.getLength(), monitor)) { // copy the whole baseClass structure to the class Structure at the given offset
classStructureDataType = EditStructureUtils.addDataTypeToStructure( EditStructureUtils.addDataTypeToStructure(classStructureDataType,
classStructureDataType,
offset.intValue(), classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor); offset.intValue(), classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor);
}
} }
// add the vbtable structure for single inheritance/virt parent case // add the vbtable structure for single inheritance/virt parent case
@ -2445,13 +2427,11 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
addVbtableToClassStructure(recoveredClass, classStructureDataType, false); addVbtableToClassStructure(recoveredClass, classStructureDataType, false);
} }
//NEW
int dataOffset = getDataOffset(recoveredClass, classStructureDataType); int dataOffset = getDataOffset(recoveredClass, classStructureDataType);
int dataLen = UNKNOWN; int dataLen = UNKNOWN;
if (dataOffset != NONE) { if (dataOffset != NONE) {
dataLen = dataLen = EditStructureUtils.getNumberOfUndefinedsStartingAtOffset(
EditStructureUtils.getNumberOfUndefinedsStartingAtOffset(classStructureDataType, classStructureDataType, dataOffset, monitor);
dataOffset, monitor);
} }
if (dataLen != UNKNOWN && dataLen > 0) { if (dataLen != UNKNOWN && dataLen > 0) {
@ -2460,23 +2440,22 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
classStructureDataType, dataLen, dataOffset); classStructureDataType, dataLen, dataOffset);
if (recoveredClassDataStruct != null) { if (recoveredClassDataStruct != null) {
classStructureDataType = // if it fits at offset or is at the end and class structure can be grown,
EditStructureUtils.addDataTypeToStructure(classStructureDataType, // copy the whole baseClass structure to the class Structure at the given offset
dataOffset, recoveredClassDataStruct, EditStructureUtils.addDataTypeToStructure(classStructureDataType, dataOffset,
classStructureDataType.getName() + "_data", monitor); recoveredClassDataStruct, classStructureDataType.getName() + "_data", monitor);
} }
} }
//NEW:
classStructureDataType = classStructureDataType =
addClassVftables(classStructureDataType, recoveredClass, vfPointerDataTypes); addClassVftables(classStructureDataType, recoveredClass, vfPointerDataTypes);
//NEW:
classStructureDataType = classStructureDataType =
addVbtableToClassStructure(recoveredClass, classStructureDataType, true); addVbtableToClassStructure(recoveredClass, classStructureDataType, true);
if (classStructureDataType.getNumComponents() == classStructureDataType.getNumDefinedComponents()) { if (classStructureDataType.getNumComponents() == classStructureDataType
.getNumDefinedComponents()) {
classStructureDataType.setPackingEnabled(true); 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 * Method to return the offset of the given class's single virtual parent
* @param recoveredClass the given class * @param recoveredClass the given class
* @return the offset of the single virtual parent or null if there is not a single virtual parent * @return the offset in the given class structure of the classes single virtual parent or NONE
* or if there is no mapping in the offset map for that parent * if cannot retrieve an offset value or if there is not a single virtual parent for the given
* class.
* @throws CancelledException if cancelled * @throws CancelledException if cancelled
* @throws AddressOutOfBoundsException if trying to access an address that does not exist in program * @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 * @throws MemoryAccessException if trying to access memory that can't be accessed
@ -2502,7 +2482,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
List<RecoveredClass> virtualParentClasses = getVirtualParentClasses(recoveredClass); List<RecoveredClass> virtualParentClasses = getVirtualParentClasses(recoveredClass);
if (virtualParentClasses.size() != 1) { if (virtualParentClasses.size() != 1) {
return null; return NONE;
} }
Map<RecoveredClass, Integer> parentOffsetMap = getBaseClassOffsetMap(recoveredClass); Map<RecoveredClass, Integer> parentOffsetMap = getBaseClassOffsetMap(recoveredClass);

View file

@ -5489,36 +5489,39 @@ public class RecoveredClassHelper {
} }
/** /**
* Method to add the given structcure component to the given structure at the given offset * Method to add the structure components from the given structureToAdd from the given starting
* @param structureDataType the structure to add to * offset to the given ending offset of the to the given structure at the given offset
* @param structureToAdd the structure to add * @param structure the structure to add to
* @param startOffset the starting offset where to add * @param structureToAdd the structure to add a subset of components from to the given structure
* @param endOffset the ending offset of the added structure * @param startOffset the starting offset of where to start adding in the container structure
* @return the updated structure * @param dataLength the total length of the data components to add
* @return true if the structure was updated or false if the components cannot be added
* @throws CancelledException if cancelled * @throws CancelledException if cancelled
*/ */
public Structure addIndividualComponentsToStructure(Structure structureDataType, public boolean addIndividualComponentsToStructure(Structure structure, Structure structureToAdd,
Structure structureToAdd, int startOffset, int endOffset) throws CancelledException { int startOffset, int dataLength) throws CancelledException {
DataTypeComponent[] definedComponents = structureToAdd.getDefinedComponents(); // this check does not allow growing of structure. It only allows adding to the structure if
for (int ii = 0; ii < definedComponents.length; ii++) { // the block of components to add will fit at the given offset
if (!EditStructureUtils.canAdd(structure, startOffset, dataLength, false,
monitor)) {
return false;
}
for (DataTypeComponent dataTypeComponent : structureToAdd.getDefinedComponents()) {
monitor.checkCanceled(); monitor.checkCanceled();
DataTypeComponent dataTypeComponent = structureToAdd.getComponent(ii); // only copy the components up to the given total dataLength to copy
if ((dataTypeComponent.getOffset() + dataTypeComponent.getLength()) > dataLength) {
int dataComponentOffset = dataTypeComponent.getOffset(); break;
if (endOffset != NONE && (dataComponentOffset + startOffset) >= endOffset) {
return structureDataType;
} }
String fieldname = dataTypeComponent.getFieldName(); structure.replaceAtOffset(startOffset + dataTypeComponent.getOffset(),
dataTypeComponent.getDataType(), -1, dataTypeComponent.getFieldName(),
structureDataType = EditStructureUtils.addDataTypeToStructure(structureDataType, dataTypeComponent.getComment());
startOffset + dataComponentOffset, dataTypeComponent.getDataType(), fieldname,
monitor);
} }
return structureDataType; return true;
} }
@ -6193,7 +6196,7 @@ public class RecoveredClassHelper {
* Method to retrieve the offset of the class data in the given structure * Method to retrieve the offset of the class data in the given structure
* @param recoveredClass the given class * @param recoveredClass the given class
* @param structure the given structure * @param structure the given structure
* @return the offset of the class data in the given structure * @return the offset of the class data in the given structure or NONE if there isn't one
* @throws CancelledException if cancelled * @throws CancelledException if cancelled
*/ */
public int getDataOffset(RecoveredClass recoveredClass, Structure structure) public int getDataOffset(RecoveredClass recoveredClass, Structure structure)
@ -8204,22 +8207,17 @@ public class RecoveredClassHelper {
monitor.checkCanceled(); monitor.checkCanceled();
// if enough empty bytes - add class vftable pointer // if enough empty bytes or can grow the structure - add class vftable pointer
if (EditStructureUtils.canAdd(classStructureDataType, vftableOffset, boolean addedToStructure =
classVftablePointer.getLength(), monitor)) { EditStructureUtils.addDataTypeToStructure(classStructureDataType, vftableOffset,
classStructureDataType =
EditStructureUtils.addDataTypeToStructure(classStructureDataType,
vftableOffset,
classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor); classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor);
if (addedToStructure) {
addedVftablePointer = true; addedVftablePointer = true;
continue; continue;
} }
// if already has a base class vftable pointer replace with main class vftablePtr // if already has a base class vftable pointer replace with main class vftablePtr
// get the item at that location // get the item at that location
//NEW: replaced with get containing
// if offset is in the middle, get the top of the component // if offset is in the middle, get the top of the component
DataTypeComponent currentComponent = DataTypeComponent currentComponent =
classStructureDataType.getComponentContaining(vftableOffset); classStructureDataType.getComponentContaining(vftableOffset);
@ -8298,16 +8296,12 @@ public class RecoveredClassHelper {
DataType vbaseStructPointer = dataTypeManager.getPointer(vbtableStructure); DataType vbaseStructPointer = dataTypeManager.getPointer(vbtableStructure);
int dataLength = vbaseStructPointer.getLength(); // if it fits at offset or is at the end and class structure can be grown,
if (EditStructureUtils.canAdd(classStructureDataType, vbtableOffset, dataLength, // copy the whole baseClass structure to the class Structure at the given offset
monitor)) { boolean addedToStructure = EditStructureUtils.addDataTypeToStructure(
classStructureDataType, vbtableOffset, vbaseStructPointer, VBTABLE_PTR, monitor);
classStructureDataType = if (!addedToStructure && overwrite && classStructureDataType
EditStructureUtils.addDataTypeToStructure(classStructureDataType, .getLength() >= (vbtableOffset + vbaseStructPointer.getLength())) {
vbtableOffset, vbaseStructPointer, VBTABLE_PTR, monitor);
}
else if (overwrite) {
classStructureDataType.replaceAtOffset(vbtableOffset, vbaseStructPointer, classStructureDataType.replaceAtOffset(vbtableOffset, vbaseStructPointer,
vbaseStructPointer.getLength(), VBTABLE_PTR, ""); vbaseStructPointer.getLength(), VBTABLE_PTR, "");
} }