Merge remote-tracking branch 'origin/Ghidra_10.1'

This commit is contained in:
Ryan Kurtz
2021-11-12 12:49:42 -05:00
12 changed files with 300 additions and 45 deletions
@@ -29,7 +29,7 @@ public interface PtySession {
* @return the status code, if applicable and implemented * @return the status code, if applicable and implemented
* @throws InterruptedException if the wait is interrupted * @throws InterruptedException if the wait is interrupted
*/ */
Integer waitExited() throws InterruptedException; int waitExited() throws InterruptedException;
/** /**
* Take the greatest efforts to terminate the session (leader and descendants) * Take the greatest efforts to terminate the session (leader and descendants)
@@ -30,7 +30,7 @@ public class LocalProcessPtySession implements PtySession {
} }
@Override @Override
public Integer waitExited() throws InterruptedException { public int waitExited() throws InterruptedException {
return process.waitFor(); return process.waitFor();
} }
@@ -28,7 +28,7 @@ public class SshPtySession implements PtySession {
} }
@Override @Override
public Integer waitExited() throws InterruptedException { public int waitExited() throws InterruptedException {
// Doesn't look like there's a clever way to wait. So do the spin sleep :( // Doesn't look like there's a clever way to wait. So do the spin sleep :(
while (!channel.isEOF()) { while (!channel.isEOF()) {
Thread.sleep(1000); Thread.sleep(1000);
@@ -65,7 +65,7 @@ public class LinuxPtyTest {
PtySession bash = PtySession bash =
pty.getChild().session(new String[] { DummyProc.which("bash") }, null); pty.getChild().session(new String[] { DummyProc.which("bash") }, null);
pty.getParent().getOutputStream().write("exit\n".getBytes()); pty.getParent().getOutputStream().write("exit\n".getBytes());
assertEquals(0, bash.waitExited().intValue()); assertEquals(0, bash.waitExited());
} }
} }
@@ -78,7 +78,7 @@ public class LinuxPtyTest {
* NOTE: Java subprocess dies with code 1 on unhandled exception. TODO: Is there a nice * NOTE: Java subprocess dies with code 1 on unhandled exception. TODO: Is there a nice
* way to distinguish whether the code is from java or the execed image? * way to distinguish whether the code is from java or the execed image?
*/ */
assertEquals(1, dies.waitExited().intValue()); assertEquals(1, dies.waitExited());
} }
} }
@@ -117,7 +117,7 @@ public class LinuxPtyTest {
while (true) { while (true) {
try { try {
assertEquals("Early exit with wrong code", expected, assertEquals("Early exit with wrong code", expected,
session.waitExited().intValue()); session.waitExited());
return; return;
} }
catch (InterruptedException e) { catch (InterruptedException e) {
@@ -159,7 +159,7 @@ public class LinuxPtyTest {
assertTrue("Not 'exit 3' or 'BASH:exit 3': '" + line + "'", assertTrue("Not 'exit 3' or 'BASH:exit 3': '" + line + "'",
Set.of("BASH:exit 3", "exit 3").contains(line)); Set.of("BASH:exit 3", "exit 3").contains(line));
assertEquals(3, bash.waitExited().intValue()); assertEquals(3, bash.waitExited());
} }
} }
@@ -214,7 +214,7 @@ public class LinuxPtyTest {
writer.flush(); writer.flush();
assertTrue(Set.of("BASH:exit 3", "exit 3").contains(reader.readLine())); assertTrue(Set.of("BASH:exit 3", "exit 3").contains(reader.readLine()));
assertEquals(3, bash.waitExited().intValue()); assertEquals(3, bash.waitExited());
} }
} }
} }
@@ -82,7 +82,7 @@ public class SshPtyTest extends AbstractGhidraHeadedIntegrationTest {
out.write("exit\n".getBytes("UTF-8")); out.write("exit\n".getBytes("UTF-8"));
out.flush(); out.flush();
new StreamPumper(pty.getParent().getInputStream(), System.out).start(); new StreamPumper(pty.getParent().getInputStream(), System.out).start();
assertEquals(0, bash.waitExited().intValue()); assertEquals(0, bash.waitExited());
} }
} }
} }
@@ -45,7 +45,7 @@ public class ApplyClassFunctionDefinitionUpdatesScript extends GhidraScript {
} }
RecoveredClassUtils classUtils = new RecoveredClassUtils(currentProgram, currentLocation, 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); Namespace classNamespace = classUtils.getClassNamespace(currentAddress);
if (classNamespace == null) { if (classNamespace == null) {
@@ -45,7 +45,7 @@ public class ApplyClassFunctionSignatureUpdatesScript extends GhidraScript {
} }
RecoveredClassUtils classUtils = new RecoveredClassUtils(currentProgram, currentLocation, 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); Namespace classNamespace = classUtils.getClassNamespace(currentAddress);
if (classNamespace == null) { if (classNamespace == null) {
@@ -121,6 +121,12 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
// show shortened class template names in class structure field names // show shortened class template names in class structure field names
private static final boolean USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS = true; 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 CLASS_DATA_STRUCT_NAME = "_data";
private static final String CONSTRUCTOR_BOOKMARK = "CONSTRUCTOR"; private static final String CONSTRUCTOR_BOOKMARK = "CONSTRUCTOR";
@@ -128,6 +134,24 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
private static final String INDETERMINATE_BOOKMARK = "INDETERMINATE"; private static final String INDETERMINATE_BOOKMARK = "INDETERMINATE";
// If replacedClassStructuresOption is set to the following, no replaced structures will be removed
// from the data type manager
private static final int DO_NOT_REMOVE_REPLACED_CLASS_STRUCTURES = 0;
// If replacedClassStructuresOption is set to the following, only empty existing class structures
// that were replaced by this script will be removed from the data type manager
private static final int REMOVE_EMPTY_REPLACED_CLASS_STRUCTURES = 1;
// If replacedClassStructuresOption is set to the following, all existing class structures that
// were replaced by this script, including non-emtpy ones, will be removed from the data type
// manager
private static final int REMOVE_ALL_REPLACED_CLASS_STRUCTURES = 2;
// NEW OPTION -
// This option allows the user to decide whether and how to remove replaced existing class structures
// using one of the above three flags
int replacedClassStructuresOption = DO_NOT_REMOVE_REPLACED_CLASS_STRUCTURES;
boolean programHasRTTIApplied = false; boolean programHasRTTIApplied = false;
boolean hasDebugSymbols; boolean hasDebugSymbols;
boolean isGcc = false; boolean isGcc = false;
@@ -162,6 +186,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
recoverClassesFromRTTI = new RTTIWindowsClassRecoverer(currentProgram, recoverClassesFromRTTI = new RTTIWindowsClassRecoverer(currentProgram,
currentLocation, state.getTool(), this, BOOKMARK_FOUND_FUNCTIONS, currentLocation, state.getTool(), this, BOOKMARK_FOUND_FUNCTIONS,
USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS, nameVfunctions, hasDebugSymbols, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS, nameVfunctions, hasDebugSymbols,
REPLACE_EXISTING_CLASS_STRUCTURES,
monitor); monitor);
} }
else if (isGcc()) { else if (isGcc()) {
@@ -182,6 +207,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
recoverClassesFromRTTI = new RTTIGccClassRecoverer(currentProgram, currentLocation, recoverClassesFromRTTI = new RTTIGccClassRecoverer(currentProgram, currentLocation,
state.getTool(), this, BOOKMARK_FOUND_FUNCTIONS, state.getTool(), this, BOOKMARK_FOUND_FUNCTIONS,
USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS, nameVfunctions, hasDebugSymbols, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS, nameVfunctions, hasDebugSymbols,
REPLACE_EXISTING_CLASS_STRUCTURES,
monitor); monitor);
} }
else { else {
@@ -275,6 +301,17 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
showGraph(graph); showGraph(graph);
} }
if (replacedClassStructuresOption == REMOVE_EMPTY_REPLACED_CLASS_STRUCTURES) {
println("Removing all empty replaced class structures from the data type manager");
recoverClassesFromRTTI.removeReplacedClassStructures(recoveredClasses, false);
}
if (replacedClassStructuresOption == REMOVE_ALL_REPLACED_CLASS_STRUCTURES) {
println(
"Removing all replaced class structures from the data type manager, including non-empty ones");
recoverClassesFromRTTI.removeReplacedClassStructures(recoveredClasses, true);
}
decompilerUtils.disposeDecompilerInterface(); decompilerUtils.disposeDecompilerInterface();
} }
@@ -40,12 +40,14 @@ public class RTTIClassRecoverer extends RecoveredClassUtils {
TaskMonitor monitor; TaskMonitor monitor;
boolean hasDebugSymbols; boolean hasDebugSymbols;
RTTIClassRecoverer(Program program, ProgramLocation location, PluginTool tool, RTTIClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates, FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
boolean nameVfunctions, boolean hasDebugSymbols, boolean nameVfunctions, boolean hasDebugSymbols, boolean replaceClassStructures,
TaskMonitor monitor) { TaskMonitor monitor) {
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions, super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions,
replaceClassStructures,
monitor); monitor);
this.program = program; this.program = program;
@@ -69,15 +69,19 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
new HashMap<RecoveredClass, Map<RecoveredClass, Long>>(); new HashMap<RecoveredClass, Map<RecoveredClass, Long>>();
boolean isDwarfLoaded; boolean isDwarfLoaded;
boolean replaceClassStructs;
public RTTIGccClassRecoverer(Program program, ProgramLocation location, PluginTool tool, public RTTIGccClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates, 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, super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions,
replaceExistingClassStructures,
isDwarfLoaded, isDwarfLoaded,
monitor); monitor);
this.isDwarfLoaded = isDwarfLoaded; this.isDwarfLoaded = isDwarfLoaded;
this.replaceClassStructs = replaceExistingClassStructures;
} }
@Override @Override
@@ -2898,12 +2902,14 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
Structure classStruct = createSimpleClassStructure(recoveredClass, vfPointerDataTypes); Structure classStruct = createSimpleClassStructure(recoveredClass, vfPointerDataTypes);
// check for DWARF -- if none add c/d/etc to class // 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) { if (!isDwarfLoaded) {
// Now that we have a class data type // Now that we have a class data type
// name constructor and destructor functions and put into the class namespace // name constructor and destructor functions and put into the class namespace
addConstructorsToClassNamespace(recoveredClass, classStruct); addConstructorsToClassNamespace(recoveredClass, classStruct);
addDestructorsToClassNamespace(recoveredClass); addDestructorsToClassNamespace(recoveredClass, classStruct);
// addNonThisDestructorsToClassNamespace(recoveredClass); // addNonThisDestructorsToClassNamespace(recoveredClass);
// addVbaseDestructorsToClassNamespace(recoveredClass); // addVbaseDestructorsToClassNamespace(recoveredClass);
// addVbtableToClassNamespace(recoveredClass); // addVbtableToClassNamespace(recoveredClass);
@@ -2914,7 +2920,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
// createIndeterminateInlineComments(recoveredClass); // createIndeterminateInlineComments(recoveredClass);
// add label on constructor destructor functions that could not be determined which were which // 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 // 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 // then empty classes will get auto-created in the wrong place
// when the vfunctions are put in the class // 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, public RTTIWindowsClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates, FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
boolean nameVFunctions, boolean isPDBLoaded, boolean nameVFunctions, boolean isPDBLoaded, boolean replaceClassStructures,
TaskMonitor monitor) throws CancelledException { TaskMonitor monitor) throws CancelledException {
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVFunctions, super(program, location, tool, api, createBookmarks, useShortTemplates, nameVFunctions,
isPDBLoaded, monitor); isPDBLoaded, replaceClassStructures, monitor);
this.isPDBLoaded = isPDBLoaded; this.isPDBLoaded = isPDBLoaded;
@@ -2245,32 +2245,35 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
applyVbtableStructure(recoveredClass); applyVbtableStructure(recoveredClass);
// pdb already has good names so only name if no pdb
if (!isPDBLoaded) {
// Now that we have a class data type // Now that we have a class data type
// name constructor and destructor functions and put into the class namespace // name constructor and destructor functions and put into the class namespace
addConstructorsToClassNamespace(recoveredClass, classStruct); // checks are internal for hasDebugSymbols since there
addDestructorsToClassNamespace(recoveredClass); // are also replace methods that need to be called either way
addConstructorsToClassNamespace(recoveredClass, classStruct);
addDestructorsToClassNamespace(recoveredClass, classStruct);
addVbaseDestructorsToClassNamespace(recoveredClass, classStruct);
if (!hasDebugSymbols) {
addNonThisDestructorsToClassNamespace(recoveredClass); addNonThisDestructorsToClassNamespace(recoveredClass);
addVbaseDestructorsToClassNamespace(recoveredClass);
addVbtableToClassNamespace(recoveredClass); addVbtableToClassNamespace(recoveredClass);
// add secondary label on functions with inlined constructors or destructors // add secondary label on functions with inlined constructors or destructors
createInlinedConstructorComments(recoveredClass); createInlinedConstructorComments(recoveredClass);
createInlinedDestructorComments(recoveredClass); createInlinedDestructorComments(recoveredClass);
createIndeterminateInlineComments(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 // This is done after the class structure is created and added to the dtmanager
// because if done before the class structures are created // because if done before the class structures are created
// then empty classes will get auto-created in the wrong place // then empty classes will get auto-created in the wrong place
// when the vfunctions are put in the class // 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 createBookmarks;
boolean useShortTemplates; boolean useShortTemplates;
boolean nameVfunctions; boolean nameVfunctions;
boolean replaceClassStructures;
public RecoveredClassUtils(Program program, ProgramLocation location, PluginTool tool, public RecoveredClassUtils(Program program, ProgramLocation location, PluginTool tool,
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates, FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
boolean nameVfunctions, TaskMonitor monitor) { boolean nameVunctions, boolean replaceClassStructures, TaskMonitor monitor) {
this.monitor = monitor; this.monitor = monitor;
this.program = program; this.program = program;
@@ -162,7 +163,8 @@ public class RecoveredClassUtils {
this.createBookmarks = createBookmarks; this.createBookmarks = createBookmarks;
this.useShortTemplates = useShortTemplates; this.useShortTemplates = useShortTemplates;
this.nameVfunctions = nameVfunctions; this.nameVfunctions = nameVunctions;
this.replaceClassStructures = replaceClassStructures;
globalNamespace = (GlobalNamespace) program.getGlobalNamespace(); globalNamespace = (GlobalNamespace) program.getGlobalNamespace();
@@ -3294,12 +3296,17 @@ public class RecoveredClassUtils {
monitor.checkCanceled(); monitor.checkCanceled();
Function constructorFunction = constructorsIterator.next(); 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 // 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 // structure and replace it with the one that was just created by the script
//deleteEmptyClassStructure(constructorFunction, className); //NEW
replaceEmptyClassStructure(constructorFunction, className, classStruct); if (replaceClassStructures) {
replaceClassStructure(constructorFunction, className, classStruct);
}
// if current decompiler function return type is a pointer then set the return type // 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 // 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 * Method to name class destructors and add them to class namespace
* @param recoveredClass current class * @param recoveredClass current class
* @param classStruct the class structure for the given class
* @throws Exception when cancelled * @throws Exception when cancelled
*/ */
public void addDestructorsToClassNamespace(RecoveredClass recoveredClass) throws Exception { public void addDestructorsToClassNamespace(RecoveredClass recoveredClass, Structure classStruct)
throws Exception {
Namespace classNamespace = recoveredClass.getClassNamespace(); Namespace classNamespace = recoveredClass.getClassNamespace();
String className = recoveredClass.getName(); String className = recoveredClass.getName();
@@ -3351,8 +3360,17 @@ public class RecoveredClassUtils {
Function destructorFunction = destructorIterator.next(); Function destructorFunction = destructorIterator.next();
String destructorName = "~" + className; String destructorName = "~" + className;
createNewSymbolAtFunction(destructorFunction, destructorName, classNamespace, true, if (nameVfunctions) {
true); 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); 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 * Method to name class vbase destructors and add them to class namespace
* @param recoveredClass current class * @param recoveredClass current class
* @param classStruct the class structure for the given class
* @throws Exception when cancelled * @throws Exception when cancelled
*/ */
public void addVbaseDestructorsToClassNamespace(RecoveredClass recoveredClass) public void addVbaseDestructorsToClassNamespace(RecoveredClass recoveredClass,
Structure classStruct)
throws Exception { throws Exception {
Namespace classNamespace = recoveredClass.getClassNamespace(); Namespace classNamespace = recoveredClass.getClassNamespace();
@@ -3395,8 +3415,18 @@ public class RecoveredClassUtils {
if (vbaseDestructorFunction != null) { if (vbaseDestructorFunction != null) {
String destructorName = VBASE_DESTRUCTOR_LABEL; String destructorName = VBASE_DESTRUCTOR_LABEL;
createNewSymbolAtFunction(vbaseDestructorFunction, destructorName, classNamespace, true, if (nameVfunctions) {
true); 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); vbaseDestructorFunction.setReturnType(DataType.VOID, SourceType.ANALYSIS);
} }
@@ -3505,6 +3535,161 @@ 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
* @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 remove existing class structures from the data type manager that were replaced by
* newly created class structures and that have the "_REPLACED" suffix on them
* @param recoveredClasses list of given recovered classes
* @param removeNonEmpty if true, remove not only the empty replaced class structures but
* also the non-empty ones.
* @throws CancelledException if cancelled
*/
public void removeReplacedClassStructures(List<RecoveredClass> recoveredClasses,
boolean removeNonEmpty) throws CancelledException {
if (recoveredClasses.isEmpty()) {
return;
}
for (RecoveredClass recoveredClass : recoveredClasses) {
monitor.checkCanceled();
// first get the new class structure and verify it exists - don't remove others if
// new one doesn't exist
DataType classStructureDataType = dataTypeManager.getDataType(
recoveredClass.getClassPath(), recoveredClass.getName());
if (classStructureDataType == null) {
continue;
}
// then find all class structures with name "<className>_REPLACED"
List<DataType> replacedClassDataTypes = new ArrayList<DataType>();
dataTypeManager.findDataTypes(recoveredClass.getName() + "_REPLACED",
replacedClassDataTypes);
if (replacedClassDataTypes.isEmpty()) {
continue;
}
for (DataType replacedClassDataType : replacedClassDataTypes) {
monitor.checkCanceled();
if (!(replacedClassDataType instanceof Structure)) {
continue;
}
if (removeNonEmpty) {
dataTypeManager.remove(replacedClassDataType, monitor);
}
else {
Structure replacedStructure = (Structure) replacedClassDataType;
if (replacedStructure.isNotYetDefined()) {
dataTypeManager.remove(replacedClassDataType, monitor);
}
}
}
}
}
/** /**
* Method to create a new symbol at the given function * Method to create a new symbol at the given function
* @param function the given function * @param function the given function
@@ -4435,11 +4620,12 @@ public class RecoveredClassUtils {
* Method to fill in the vftable structure with pointers to virtual function signature data types * Method to fill in the vftable structure with pointers to virtual function signature data types
* @param recoveredClass the current class to be processed * @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 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 CancelledException when cancelled
* @throws Exception if other exception * @throws Exception if other exception
*/ */
public void fillInAndApplyVftableStructAndNameVfunctions(RecoveredClass recoveredClass, 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 //create function definition for each virtual function and put in vftable structure and
// data subfolder // data subfolder
@@ -4468,6 +4654,7 @@ public class RecoveredClassUtils {
nameVfunctions(recoveredClass, vftableAddress, vftableStructureName); nameVfunctions(recoveredClass, vftableAddress, vftableStructureName);
} }
List<Function> vFunctions = recoveredClass.getVirtualFunctions(vftableAddress); List<Function> vFunctions = recoveredClass.getVirtualFunctions(vftableAddress);
int vfunctionNumber = 1; int vfunctionNumber = 1;
Iterator<Function> vfIterator = vFunctions.iterator(); Iterator<Function> vfIterator = vFunctions.iterator();
@@ -4483,6 +4670,13 @@ public class RecoveredClassUtils {
continue; 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 // get the classPath of highest level parent with vfAddress in their vftable
classPath = classPath =
getCategoryPathForFunctionSignature(vfunction, recoveredClass, vftableAddress); getCategoryPathForFunctionSignature(vfunction, recoveredClass, vftableAddress);
@@ -5008,9 +5202,11 @@ public class RecoveredClassUtils {
/** /**
* Method to add label on constructor or destructors but couldn't tell which * Method to add label on constructor or destructors but couldn't tell which
* @param recoveredClass current class * @param recoveredClass current class
* @param classStruct the class structure for the given class
* @throws Exception when cancelled * @throws Exception when cancelled
*/ */
public void createIndeterminateLabels(RecoveredClass recoveredClass) throws Exception { public void createIndeterminateLabels(RecoveredClass recoveredClass, Structure classStruct)
throws Exception {
Namespace classNamespace = recoveredClass.getClassNamespace(); Namespace classNamespace = recoveredClass.getClassNamespace();
String className = recoveredClass.getName(); String className = recoveredClass.getName();
@@ -5020,8 +5216,18 @@ public class RecoveredClassUtils {
while (unknownsIterator.hasNext()) { while (unknownsIterator.hasNext()) {
monitor.checkCanceled(); monitor.checkCanceled();
Function indeterminateFunction = unknownsIterator.next(); 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);
}
} }
} }