diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/PtySession.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/PtySession.java index e24a04c8ec..631147092b 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/PtySession.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/PtySession.java @@ -29,7 +29,7 @@ public interface PtySession { * @return the status code, if applicable and implemented * @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) diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/local/LocalProcessPtySession.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/local/LocalProcessPtySession.java index a4d522851b..ddf26b2757 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/local/LocalProcessPtySession.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/local/LocalProcessPtySession.java @@ -30,7 +30,7 @@ public class LocalProcessPtySession implements PtySession { } @Override - public Integer waitExited() throws InterruptedException { + public int waitExited() throws InterruptedException { return process.waitFor(); } diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/ssh/SshPtySession.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/ssh/SshPtySession.java index e1d04c693e..0cbce41e3b 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/ssh/SshPtySession.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/ssh/SshPtySession.java @@ -28,7 +28,7 @@ public class SshPtySession implements PtySession { } @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 :( while (!channel.isEOF()) { Thread.sleep(1000); diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/test/java/agent/gdb/pty/linux/LinuxPtyTest.java b/Ghidra/Debug/Debugger-agent-gdb/src/test/java/agent/gdb/pty/linux/LinuxPtyTest.java index 46697ccfe8..4530c6db87 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/test/java/agent/gdb/pty/linux/LinuxPtyTest.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/test/java/agent/gdb/pty/linux/LinuxPtyTest.java @@ -65,7 +65,7 @@ public class LinuxPtyTest { PtySession bash = pty.getChild().session(new String[] { DummyProc.which("bash") }, null); 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 * 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) { try { assertEquals("Early exit with wrong code", expected, - session.waitExited().intValue()); + session.waitExited()); return; } catch (InterruptedException e) { @@ -159,7 +159,7 @@ public class LinuxPtyTest { assertTrue("Not 'exit 3' or 'BASH:exit 3': '" + 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(); assertTrue(Set.of("BASH:exit 3", "exit 3").contains(reader.readLine())); - assertEquals(3, bash.waitExited().intValue()); + assertEquals(3, bash.waitExited()); } } } diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/test/java/agent/gdb/pty/ssh/SshPtyTest.java b/Ghidra/Debug/Debugger-agent-gdb/src/test/java/agent/gdb/pty/ssh/SshPtyTest.java index 39d61096bb..732827b969 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/test/java/agent/gdb/pty/ssh/SshPtyTest.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/test/java/agent/gdb/pty/ssh/SshPtyTest.java @@ -82,7 +82,7 @@ public class SshPtyTest extends AbstractGhidraHeadedIntegrationTest { out.write("exit\n".getBytes("UTF-8")); out.flush(); new StreamPumper(pty.getParent().getInputStream(), System.out).start(); - assertEquals(0, bash.waitExited().intValue()); + assertEquals(0, bash.waitExited()); } } } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionDefinitionUpdatesScript.java b/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionDefinitionUpdatesScript.java index d949dd98eb..25b6922a49 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionDefinitionUpdatesScript.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionDefinitionUpdatesScript.java @@ -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) { diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionSignatureUpdatesScript.java b/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionSignatureUpdatesScript.java index 3db3b3c858..6ce4321839 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionSignatureUpdatesScript.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionSignatureUpdatesScript.java @@ -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) { diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java b/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java index 107a73a843..b98cb2ba67 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java @@ -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"; @@ -128,6 +134,24 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { 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 hasDebugSymbols; boolean isGcc = false; @@ -162,6 +186,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 +207,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 { @@ -275,6 +301,17 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { 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(); } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIClassRecoverer.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIClassRecoverer.java index daba6d4698..408765ac17 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIClassRecoverer.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIClassRecoverer.java @@ -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; diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java index 74f872de7b..a678e60417 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java @@ -69,15 +69,19 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { new HashMap>(); 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); } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java index 356fbfde37..ddadec4088 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java @@ -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); } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassUtils.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassUtils.java index 7b6e1fadc6..711bae1f52 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassUtils.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassUtils.java @@ -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,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 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 "_REPLACED" + List replacedClassDataTypes = new ArrayList(); + 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 * @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 * @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 vftableToStructureMap) throws CancelledException, Exception { + Map vftableToStructureMap, Structure classStruct) throws CancelledException, Exception { //create function definition for each virtual function and put in vftable structure and // data subfolder @@ -4468,6 +4654,7 @@ public class RecoveredClassUtils { nameVfunctions(recoveredClass, vftableAddress, vftableStructureName); } + List vFunctions = recoveredClass.getVirtualFunctions(vftableAddress); int vfunctionNumber = 1; Iterator vfIterator = vFunctions.iterator(); @@ -4483,6 +4670,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 +5202,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 +5216,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); + } } }