mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
GP-1506 Refactored to put new class structure code in RecoverClassHelper then added calls to it in gcc create structure code. Plus some code refactoring and cleanup.
This commit is contained in:
parent
3219e2e69f
commit
9567e2f1ea
7 changed files with 244 additions and 336 deletions
|
@ -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<Symbol> classVftableSymbols = classUtils.getClassVftableSymbols(classNamespace);
|
||||
List<Symbol> 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<Object> 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<Structure> structuresOnList = classUtils.getStructuresOnList(changedItems);
|
||||
List<Structure> structuresOnList = classHelper.getStructuresOnList(changedItems);
|
||||
List<FunctionDefinition> functionDefinitionsOnList =
|
||||
classUtils.getFunctionDefinitionsOnList(changedItems);
|
||||
List<Function> functionsOnList = classUtils.getFunctionsOnList(changedItems);
|
||||
classHelper.getFunctionDefinitionsOnList(changedItems);
|
||||
List<Function> functionsOnList = classHelper.getFunctionsOnList(changedItems);
|
||||
|
||||
println();
|
||||
println("Updated structures:");
|
||||
|
|
|
@ -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<Symbol> classVftableSymbols = classUtils.getClassVftableSymbols(classNamespace);
|
||||
List<Symbol> 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<Object> 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<Structure> structuresOnList = classUtils.getStructuresOnList(changedItems);
|
||||
List<Structure> structuresOnList = classHelper.getStructuresOnList(changedItems);
|
||||
List<FunctionDefinition> functionDefinitionsOnList =
|
||||
classUtils.getFunctionDefinitionsOnList(changedItems);
|
||||
List<Function> functionsOnList = classUtils.getFunctionsOnList(changedItems);
|
||||
classHelper.getFunctionDefinitionsOnList(changedItems);
|
||||
List<Function> functionsOnList = classHelper.getFunctionsOnList(changedItems);
|
||||
|
||||
println();
|
||||
println("Updated structures:");
|
||||
|
|
|
@ -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
|
||||
|
@ -254,74 +246,72 @@ class EditStructureUtils {
|
|||
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
|
||||
|
@ -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++;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<Address, DataType> vfPointerDataTypes)
|
||||
throws CancelledException, IllegalArgumentException {
|
||||
|
||||
if (vfPointerDataTypes == null) {
|
||||
return classStructureDataType;
|
||||
}
|
||||
|
||||
if (!isClassOffsetToVftableMapComplete(recoveredClass)) {
|
||||
Msg.debug(this,
|
||||
"class vftable offset map for " + recoveredClass.getName() + " is not complete");
|
||||
}
|
||||
|
||||
// iterate over the set of offsets to vftables for the class and if nothing
|
||||
// is already at the offset, add the vftables
|
||||
Map<Integer, Address> classOffsetToVftableMap = recoveredClass.getClassOffsetToVftableMap();
|
||||
Set<Integer> classVftableOffsets = classOffsetToVftableMap.keySet();
|
||||
|
||||
if (classVftableOffsets.isEmpty()) {
|
||||
return classStructureDataType;
|
||||
}
|
||||
|
||||
for (Integer offset : classVftableOffsets) {
|
||||
monitor.checkCanceled();
|
||||
|
||||
Address vftableAddress = classOffsetToVftableMap.get(offset);
|
||||
|
||||
int vftableOffset = offset.intValue();
|
||||
|
||||
DataType classVftablePointer = vfPointerDataTypes.get(vftableAddress);
|
||||
|
||||
boolean addedVftablePointer = false;
|
||||
while (!addedVftablePointer) {
|
||||
|
||||
monitor.checkCanceled();
|
||||
|
||||
// if enough empty bytes - add class vftable pointer
|
||||
if (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
|
||||
|
|
|
@ -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<Address, DataType> vfPointerDataTypes)
|
||||
throws CancelledException, IllegalArgumentException {
|
||||
|
||||
Map<Integer, Address> classOffsetToVftableMap = recoveredClass.getClassOffsetToVftableMap();
|
||||
Set<Integer> 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;
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue