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;
}
/**
* 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,10 +296,22 @@ 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) {
if (isGrowthAllowed) {
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 (component.getOffset() != offset) {

View file

@ -2857,14 +2857,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
@ -2905,14 +2900,11 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
" : structure should exist but doesn't.");
}
if (EditStructureUtils.canAdd(classStructureDataType, parentOffset,
baseClassStructure.getLength(), monitor)) {
classStructureDataType =
EditStructureUtils.addDataTypeToStructure(classStructureDataType,
parentOffset,
// 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);
}
}
}
@ -2920,9 +2912,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
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) {
@ -2931,9 +2922,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);
}
}

View file

@ -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<Address, DataType> vfPointerDataTypes) throws Exception {
@ -2353,40 +2351,31 @@ 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,
// 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 {
// else need to fill in the virtually inherited ones
// 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;
if (EditStructureUtils.canAdd(classStructureDataType, baseClassOffset,
baseClassStructure.getLength(), monitor)) {
classStructureDataType =
// 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);
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,
// 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<RecoveredClass> virtualParentClasses = getVirtualParentClasses(recoveredClass);
if (virtualParentClasses.size() != 1) {
return null;
return NONE;
}
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
* @param structureDataType the structure to add to
* @param structureToAdd the structure to add
* @param startOffset the starting offset where to add
* @param endOffset the ending offset of the added structure
* @return the updated structure
* Method to add the structure components from the given structureToAdd from the given starting
* offset to the given ending offset of the to the given structure at the given offset
* @param structure the structure to add to
* @param structureToAdd the structure to add a subset of components from to the given structure
* @param startOffset the starting offset of where to start adding in the container 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
*/
public Structure addIndividualComponentsToStructure(Structure structureDataType,
Structure structureToAdd, int startOffset, int endOffset) throws CancelledException {
public boolean addIndividualComponentsToStructure(Structure structure, Structure structureToAdd,
int startOffset, int dataLength) throws CancelledException {
DataTypeComponent[] definedComponents = structureToAdd.getDefinedComponents();
for (int ii = 0; ii < definedComponents.length; ii++) {
// this check does not allow growing of structure. It only allows adding to the structure if
// 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();
DataTypeComponent dataTypeComponent = structureToAdd.getComponent(ii);
int dataComponentOffset = dataTypeComponent.getOffset();
if (endOffset != NONE && (dataComponentOffset + startOffset) >= endOffset) {
return structureDataType;
// only copy the components up to the given total dataLength to copy
if ((dataTypeComponent.getOffset() + dataTypeComponent.getLength()) > dataLength) {
break;
}
String fieldname = dataTypeComponent.getFieldName();
structureDataType = EditStructureUtils.addDataTypeToStructure(structureDataType,
startOffset + dataComponentOffset, dataTypeComponent.getDataType(), fieldname,
monitor);
structure.replaceAtOffset(startOffset + dataTypeComponent.getOffset(),
dataTypeComponent.getDataType(), -1, dataTypeComponent.getFieldName(),
dataTypeComponent.getComment());
}
return structureDataType;
return true;
}
@ -6193,7 +6196,7 @@ public class RecoveredClassHelper {
* Method to retrieve the offset of the class data in the given structure
* @param recoveredClass the given class
* @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
*/
public int getDataOffset(RecoveredClass recoveredClass, Structure structure)
@ -8204,22 +8207,17 @@ public class RecoveredClassHelper {
monitor.checkCanceled();
// if enough empty bytes - add class vftable pointer
if (EditStructureUtils.canAdd(classStructureDataType, vftableOffset,
classVftablePointer.getLength(), monitor)) {
classStructureDataType =
EditStructureUtils.addDataTypeToStructure(classStructureDataType,
vftableOffset,
// if enough empty bytes or can grow the structure - add class vftable pointer
boolean addedToStructure =
EditStructureUtils.addDataTypeToStructure(classStructureDataType, vftableOffset,
classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor);
if (addedToStructure) {
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);
@ -8298,16 +8296,12 @@ public class RecoveredClassHelper {
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) {
// 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
boolean addedToStructure = EditStructureUtils.addDataTypeToStructure(
classStructureDataType, vbtableOffset, vbaseStructPointer, VBTABLE_PTR, monitor);
if (!addedToStructure && overwrite && classStructureDataType
.getLength() >= (vbtableOffset + vbaseStructPointer.getLength())) {
classStructureDataType.replaceAtOffset(vbtableOffset, vbaseStructPointer,
vbaseStructPointer.getLength(), VBTABLE_PTR, "");
}