Merge remote-tracking branch 'origin/GP-1464_ghidra007_ReplacePdbClassDataTypesInClassMethods--SQUASHED' into Ghidra_10.1

This commit is contained in:
ghidra1
2021-11-10 16:34:03 -05:00
7 changed files with 207 additions and 36 deletions
@@ -45,7 +45,7 @@ public class ApplyClassFunctionDefinitionUpdatesScript extends GhidraScript {
}
RecoveredClassUtils classUtils = new RecoveredClassUtils(currentProgram, currentLocation,
state.getTool(), this, false, false, false, monitor);
state.getTool(), this, false, false, false, false, monitor);
Namespace classNamespace = classUtils.getClassNamespace(currentAddress);
if (classNamespace == null) {
@@ -45,7 +45,7 @@ public class ApplyClassFunctionSignatureUpdatesScript extends GhidraScript {
}
RecoveredClassUtils classUtils = new RecoveredClassUtils(currentProgram, currentLocation,
state.getTool(), this, false, false, false, monitor);
state.getTool(), this, false, false, false, false, monitor);
Namespace classNamespace = classUtils.getClassNamespace(currentAddress);
if (classNamespace == null) {
@@ -121,6 +121,12 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
// show shortened class template names in class structure field names
private static final boolean USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS = true;
// replace defined existing class structures (ie pdb, fid, demangler, or other)with ones created by
// this script and rename the existing ones with a _REPLACED suffix
// NOTE: currently does not replace DWARF
// NEW OPTION:
private static final boolean REPLACE_EXISTING_CLASS_STRUCTURES = true;
private static final String CLASS_DATA_STRUCT_NAME = "_data";
private static final String CONSTRUCTOR_BOOKMARK = "CONSTRUCTOR";
@@ -162,6 +168,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
recoverClassesFromRTTI = new RTTIWindowsClassRecoverer(currentProgram,
currentLocation, state.getTool(), this, BOOKMARK_FOUND_FUNCTIONS,
USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS, nameVfunctions, hasDebugSymbols,
REPLACE_EXISTING_CLASS_STRUCTURES,
monitor);
}
else if (isGcc()) {
@@ -182,6 +189,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
recoverClassesFromRTTI = new RTTIGccClassRecoverer(currentProgram, currentLocation,
state.getTool(), this, BOOKMARK_FOUND_FUNCTIONS,
USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS, nameVfunctions, hasDebugSymbols,
REPLACE_EXISTING_CLASS_STRUCTURES,
monitor);
}
else {
@@ -40,12 +40,14 @@ public class RTTIClassRecoverer extends RecoveredClassUtils {
TaskMonitor monitor;
boolean hasDebugSymbols;
RTTIClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
boolean nameVfunctions, boolean hasDebugSymbols,
boolean nameVfunctions, boolean hasDebugSymbols, boolean replaceClassStructures,
TaskMonitor monitor) {
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions,
replaceClassStructures,
monitor);
this.program = program;
@@ -69,15 +69,19 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
new HashMap<RecoveredClass, Map<RecoveredClass, Long>>();
boolean isDwarfLoaded;
boolean replaceClassStructs;
public RTTIGccClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
boolean nameVfunctions, boolean isDwarfLoaded, TaskMonitor monitor) {
boolean nameVfunctions, boolean isDwarfLoaded, boolean replaceExistingClassStructures,
TaskMonitor monitor) {
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions,
replaceExistingClassStructures,
isDwarfLoaded,
monitor);
this.isDwarfLoaded = isDwarfLoaded;
this.replaceClassStructs = replaceExistingClassStructures;
}
@Override
@@ -2898,12 +2902,14 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
Structure classStruct = createSimpleClassStructure(recoveredClass, vfPointerDataTypes);
// check for DWARF -- if none add c/d/etc to class
//TODO: if decide to replace dwarf data types then remove this check so the replaces
// in the following methods can replace the dwarf data types
if (!isDwarfLoaded) {
// Now that we have a class data type
// name constructor and destructor functions and put into the class namespace
addConstructorsToClassNamespace(recoveredClass, classStruct);
addDestructorsToClassNamespace(recoveredClass);
addDestructorsToClassNamespace(recoveredClass, classStruct);
// addNonThisDestructorsToClassNamespace(recoveredClass);
// addVbaseDestructorsToClassNamespace(recoveredClass);
// addVbtableToClassNamespace(recoveredClass);
@@ -2914,7 +2920,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
// createIndeterminateInlineComments(recoveredClass);
// add label on constructor destructor functions that could not be determined which were which
createIndeterminateLabels(recoveredClass);
createIndeterminateLabels(recoveredClass, classStruct);
}
// This is done after the class structure is created and added to the dtmanager
@@ -2922,7 +2928,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
// then empty classes will get auto-created in the wrong place
// when the vfunctions are put in the class
fillInAndApplyVftableStructAndNameVfunctions(recoveredClass, vfPointerDataTypes);
fillInAndApplyVftableStructAndNameVfunctions(recoveredClass, vfPointerDataTypes,
classStruct);
}
@@ -69,11 +69,11 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
public RTTIWindowsClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
boolean nameVFunctions, boolean isPDBLoaded,
boolean nameVFunctions, boolean isPDBLoaded, boolean replaceClassStructures,
TaskMonitor monitor) throws CancelledException {
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVFunctions,
isPDBLoaded, monitor);
isPDBLoaded, replaceClassStructures, monitor);
this.isPDBLoaded = isPDBLoaded;
@@ -2245,32 +2245,35 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
applyVbtableStructure(recoveredClass);
// pdb already has good names so only name if no pdb
if (!isPDBLoaded) {
// Now that we have a class data type
// name constructor and destructor functions and put into the class namespace
addConstructorsToClassNamespace(recoveredClass, classStruct);
addDestructorsToClassNamespace(recoveredClass);
// Now that we have a class data type
// name constructor and destructor functions and put into the class namespace
// checks are internal for hasDebugSymbols since there
// are also replace methods that need to be called either way
addConstructorsToClassNamespace(recoveredClass, classStruct);
addDestructorsToClassNamespace(recoveredClass, classStruct);
addVbaseDestructorsToClassNamespace(recoveredClass, classStruct);
if (!hasDebugSymbols) {
addNonThisDestructorsToClassNamespace(recoveredClass);
addVbaseDestructorsToClassNamespace(recoveredClass);
addVbtableToClassNamespace(recoveredClass);
// add secondary label on functions with inlined constructors or destructors
createInlinedConstructorComments(recoveredClass);
createInlinedDestructorComments(recoveredClass);
createIndeterminateInlineComments(recoveredClass);
// add label on constructor destructor functions that could not be determined which were which
createIndeterminateLabels(recoveredClass);
}
// add label on constructor destructor functions that could not be determined which were which
createIndeterminateLabels(recoveredClass, classStruct);
// This is done after the class structure is created and added to the dtmanager
// because if done before the class structures are created
// then empty classes will get auto-created in the wrong place
// when the vfunctions are put in the class
fillInAndApplyVftableStructAndNameVfunctions(recoveredClass, vfPointerDataTypes);
fillInAndApplyVftableStructAndNameVfunctions(recoveredClass, vfPointerDataTypes,
classStruct);
}
@@ -144,10 +144,11 @@ public class RecoveredClassUtils {
boolean createBookmarks;
boolean useShortTemplates;
boolean nameVfunctions;
boolean replaceClassStructures;
public RecoveredClassUtils(Program program, ProgramLocation location, PluginTool tool,
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
boolean nameVfunctions, TaskMonitor monitor) {
boolean nameVunctions, boolean replaceClassStructures, TaskMonitor monitor) {
this.monitor = monitor;
this.program = program;
@@ -162,7 +163,8 @@ public class RecoveredClassUtils {
this.createBookmarks = createBookmarks;
this.useShortTemplates = useShortTemplates;
this.nameVfunctions = nameVfunctions;
this.nameVfunctions = nameVunctions;
this.replaceClassStructures = replaceClassStructures;
globalNamespace = (GlobalNamespace) program.getGlobalNamespace();
@@ -3294,12 +3296,17 @@ public class RecoveredClassUtils {
monitor.checkCanceled();
Function constructorFunction = constructorsIterator.next();
createNewSymbolAtFunction(constructorFunction, className, classNamespace, true, true);
if (nameVfunctions) {
createNewSymbolAtFunction(constructorFunction, className, classNamespace, true,
true);
}
// check to see if the "this" data type is an empty placeholder for the class
// structure and replace it with the one that was just created by the script
//deleteEmptyClassStructure(constructorFunction, className);
replaceEmptyClassStructure(constructorFunction, className, classStruct);
//NEW
if (replaceClassStructures) {
replaceClassStructure(constructorFunction, className, classStruct);
}
// if current decompiler function return type is a pointer then set the return type
// to a pointer to the class structure, otherwise if it is a void, make it a void so the
@@ -3337,9 +3344,11 @@ public class RecoveredClassUtils {
/**
* Method to name class destructors and add them to class namespace
* @param recoveredClass current class
* @param classStruct the class structure for the given class
* @throws Exception when cancelled
*/
public void addDestructorsToClassNamespace(RecoveredClass recoveredClass) throws Exception {
public void addDestructorsToClassNamespace(RecoveredClass recoveredClass, Structure classStruct)
throws Exception {
Namespace classNamespace = recoveredClass.getClassNamespace();
String className = recoveredClass.getName();
@@ -3351,8 +3360,17 @@ public class RecoveredClassUtils {
Function destructorFunction = destructorIterator.next();
String destructorName = "~" + className;
createNewSymbolAtFunction(destructorFunction, destructorName, classNamespace, true,
true);
if (nameVfunctions) {
createNewSymbolAtFunction(destructorFunction, destructorName, classNamespace, true,
true);
}
// check to see if the "this" data type is an empty placeholder for the class
// structure and replace it with the one that was just created by the script
//NEW
if (replaceClassStructures) {
replaceClassStructure(destructorFunction, className, classStruct);
}
destructorFunction.setReturnType(DataType.VOID, SourceType.ANALYSIS);
}
@@ -3384,9 +3402,11 @@ public class RecoveredClassUtils {
/**
* Method to name class vbase destructors and add them to class namespace
* @param recoveredClass current class
* @param classStruct the class structure for the given class
* @throws Exception when cancelled
*/
public void addVbaseDestructorsToClassNamespace(RecoveredClass recoveredClass)
public void addVbaseDestructorsToClassNamespace(RecoveredClass recoveredClass,
Structure classStruct)
throws Exception {
Namespace classNamespace = recoveredClass.getClassNamespace();
@@ -3395,8 +3415,18 @@ public class RecoveredClassUtils {
if (vbaseDestructorFunction != null) {
String destructorName = VBASE_DESTRUCTOR_LABEL;
createNewSymbolAtFunction(vbaseDestructorFunction, destructorName, classNamespace, true,
true);
if (nameVfunctions) {
createNewSymbolAtFunction(vbaseDestructorFunction, destructorName, classNamespace,
true, true);
}
// check to see if the "this" data type is an empty placeholder for the class
// structure and replace it with the one that was just created by the script
//NEW
if (replaceClassStructures) {
replaceClassStructure(vbaseDestructorFunction, recoveredClass.getName(),
classStruct);
}
vbaseDestructorFunction.setReturnType(DataType.VOID, SourceType.ANALYSIS);
}
@@ -3505,6 +3535,106 @@ public class RecoveredClassUtils {
}
}
/**
* 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
* @param className the given class name
* @param newClassStructure the new structure to replace the old with
* @throws DataTypeDependencyException if there is a data dependency exception when replacing
* @throws CancelledException if cancelled
*/
public void replaceClassStructure(Function function, String className,
Structure newClassStructure) throws DataTypeDependencyException, CancelledException {
Parameter thisParam = function.getParameter(0);
if (thisParam == null) {
return;
}
DataType dataType = thisParam.getDataType();
if (dataType instanceof Pointer) {
Pointer ptr = (Pointer) dataType;
DataType baseDataType = ptr.getDataType();
if (!baseDataType.equals(newClassStructure) &&
baseDataType.getName().equals(className)) {
// check if fid demangler or pdb - don't replace user ones
if (!isReplaceableType(function.getEntryPoint(), baseDataType)) {
return;
}
// create copy of existing one
DataType baseDataTypeCopy = baseDataType.copy(dataTypeManager);
renameDataType(baseDataTypeCopy, baseDataType.getName() + "_REPLACED");
// replace the other with the new one
dataTypeManager.replaceDataType(baseDataType, newClassStructure, false);
// // remove original folder if it is empty after the replace
// in future if decide to just remove the other ones, then do the following
// CategoryPath originalPath = baseDataType.getCategoryPath();
// Category category = dataTypeManager.getCategory(originalPath);
// Category parentCategory = category.getParent();
// if (parentCategory != null) {
// parentCategory.removeEmptyCategory(category.getName(), monitor);
// }
}
}
}
private void renameDataType(DataType dataType, String name) throws CancelledException {
boolean renamed = false;
int oneup = 2;
while (!renamed) {
monitor.checkCanceled();
try {
dataType.setName(name);
dataTypeManager.resolve(dataType, DataTypeConflictHandler.DEFAULT_HANDLER);
renamed = true;
}
catch (InvalidNameException | DuplicateNameException e) {
name = name + oneup++;
renamed = false;
}
}
}
private boolean isReplaceableType(Address address, DataType dataType) {
// return false if it isn't even a structure
if (!(dataType instanceof Structure)) {
return false;
}
String categoryPath = dataType.getPathName();
if (categoryPath.startsWith("/Demangler")) {
return true;
}
if (categoryPath.contains(".pdb")) {
return true;
}
//TODO: decide whether to replace dwarf or not
// test to see if the data type is an empty structure with "PlaceHolder Class Structure" in
// the description
Structure structure = (Structure) dataType;
if (structure.isNotYetDefined() &&
structure.getDescription().equals("PlaceHolder Class Structure")) {
return true;
}
if (program.getBookmarkManager().getBookmark(address, BookmarkType.ANALYSIS,
"Function ID Analyzer") != null) {
return true;
}
return false;
}
/**
* Method to create a new symbol at the given function
* @param function the given function
@@ -4435,11 +4565,12 @@ public class RecoveredClassUtils {
* Method to fill in the vftable structure with pointers to virtual function signature data types
* @param recoveredClass the current class to be processed
* @param vftableToStructureMap the map from the class's vftables to the correct vftable structure data type
* @param classStruct the class structure for the given class
* @throws CancelledException when cancelled
* @throws Exception if other exception
*/
public void fillInAndApplyVftableStructAndNameVfunctions(RecoveredClass recoveredClass,
Map<Address, DataType> vftableToStructureMap) throws CancelledException, Exception {
Map<Address, DataType> vftableToStructureMap, Structure classStruct) throws CancelledException, Exception {
//create function definition for each virtual function and put in vftable structure and
// data subfolder
@@ -4468,6 +4599,7 @@ public class RecoveredClassUtils {
nameVfunctions(recoveredClass, vftableAddress, vftableStructureName);
}
List<Function> vFunctions = recoveredClass.getVirtualFunctions(vftableAddress);
int vfunctionNumber = 1;
Iterator<Function> vfIterator = vFunctions.iterator();
@@ -4483,6 +4615,13 @@ public class RecoveredClassUtils {
continue;
}
// check to see if the "this" data type is an empty placeholder for the class
// structure and replace it with the one that was just created by the script
//NEW
if (replaceClassStructures) {
replaceClassStructure(vfunction, recoveredClass.getName(), classStruct);
}
// get the classPath of highest level parent with vfAddress in their vftable
classPath =
getCategoryPathForFunctionSignature(vfunction, recoveredClass, vftableAddress);
@@ -5008,9 +5147,11 @@ public class RecoveredClassUtils {
/**
* Method to add label on constructor or destructors but couldn't tell which
* @param recoveredClass current class
* @param classStruct the class structure for the given class
* @throws Exception when cancelled
*/
public void createIndeterminateLabels(RecoveredClass recoveredClass) throws Exception {
public void createIndeterminateLabels(RecoveredClass recoveredClass, Structure classStruct)
throws Exception {
Namespace classNamespace = recoveredClass.getClassNamespace();
String className = recoveredClass.getName();
@@ -5020,8 +5161,18 @@ public class RecoveredClassUtils {
while (unknownsIterator.hasNext()) {
monitor.checkCanceled();
Function indeterminateFunction = unknownsIterator.next();
createNewSymbolAtFunction(indeterminateFunction,
className + "_Constructor_or_Destructor", classNamespace, false, false);
if (nameVfunctions) {
createNewSymbolAtFunction(indeterminateFunction,
className + "_Constructor_or_Destructor", classNamespace, false, false);
}
// check to see if the "this" data type is an empty placeholder for the class
// structure and replace it with the one that was just created by the script
//NEW
if (replaceClassStructures) {
replaceClassStructure(indeterminateFunction, className, classStruct);
}
}
}