diff --git a/Ghidra/Features/Base/ghidra_scripts/GraphClassesScript.java b/Ghidra/Features/Base/ghidra_scripts/GraphClassesScript.java index ba9fcb0c4f..8de389af04 100644 --- a/Ghidra/Features/Base/ghidra_scripts/GraphClassesScript.java +++ b/Ghidra/Features/Base/ghidra_scripts/GraphClassesScript.java @@ -24,11 +24,18 @@ import ghidra.app.services.GraphDisplayBroker; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.data.*; import ghidra.service.graph.*; +import ghidra.util.WebColors; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; public class GraphClassesScript extends GhidraScript { + private static final String NO_INHERITANCE = "No Inheritance"; + private static final String SINGLE_INHERITANCE = "Single Inheritance"; + private static final String MULTIPLE_INHERITANCE = "Multiple Inheritance"; + private static final String VIRTUAL_INHERITANCE = "Virtual Inheritance"; + private static final String NON_VIRTUAL_INHERITANCE = "Non-virtual Inheritance"; + List classStructures = new ArrayList(); @Override @@ -107,7 +114,15 @@ public class GraphClassesScript extends GhidraScript { */ private AttributedGraph createGraph() throws Exception { - AttributedGraph g = new AttributedGraph("Test Graph", new EmptyGraphType()); + GraphType graphType = + new GraphTypeBuilder("Class Hierarchy Graph").vertexType(NO_INHERITANCE) + .vertexType(SINGLE_INHERITANCE) + .vertexType(MULTIPLE_INHERITANCE) + .edgeType(NON_VIRTUAL_INHERITANCE) + .edgeType(VIRTUAL_INHERITANCE) + .build(); + + AttributedGraph g = new AttributedGraph("Recovered Classes Graph", graphType); for (Structure classStructure : classStructures) { @@ -176,24 +191,27 @@ public class GraphClassesScript extends GhidraScript { AttributedEdge edge = g.addEdge(parentVertex, classVertex); if (isVirtualParent) { - edge.setAttribute("Color", "Orange"); + edge.setEdgeType(VIRTUAL_INHERITANCE); + } + else { + // else leave it default lime green + edge.setEdgeType(NON_VIRTUAL_INHERITANCE); } - // else leave it default lime green description = removeClassSubstring(description, parentName); } // no parent = blue vertex if (numParents == 0) { - classVertex.setAttribute("Color", "Blue"); + classVertex.setVertexType(NO_INHERITANCE); } // single parent = green vertex else if (numParents == 1) { - classVertex.setAttribute("Color", "Green"); + classVertex.setVertexType(SINGLE_INHERITANCE); } // multiple parents = red vertex else { - classVertex.setAttribute("Color", "Red"); + classVertex.setVertexType(MULTIPLE_INHERITANCE); } } @@ -295,7 +313,20 @@ public class GraphClassesScript extends GhidraScript { GraphDisplayBroker broker = tool.getService(GraphDisplayBroker.class); GraphDisplayProvider service = broker.getGraphDisplayProvider("Default Graph Display"); display = service.getGraphDisplay(false, TaskMonitor.DUMMY); - display.setGraph(graph, "test graph", false, TaskMonitor.DUMMY); + + GraphDisplayOptions graphOptions = new GraphDisplayOptionsBuilder(graph.getGraphType()) + .vertex(NO_INHERITANCE, VertexShape.RECTANGLE, WebColors.BLUE) + .vertex(SINGLE_INHERITANCE, VertexShape.RECTANGLE, WebColors.GREEN) + .vertex(MULTIPLE_INHERITANCE, VertexShape.RECTANGLE, WebColors.RED) + .edge(NON_VIRTUAL_INHERITANCE, WebColors.LIME_GREEN) + .edge(VIRTUAL_INHERITANCE, WebColors.ORANGE) + .defaultVertexColor(WebColors.PURPLE) + .defaultEdgeColor(WebColors.PURPLE) + .defaultLayoutAlgorithm("Compact Hierarchical") + .build(); + + display.setGraph(graph, graphOptions, + "Recovered Classes Graph", false, TaskMonitor.DUMMY); } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java b/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java index b98cb2ba67..b1be3d4172 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java @@ -35,7 +35,7 @@ // this script and default vfunctions named by this script are likely to change in the future // once an official design for Object Oriented representation is determined. // NOTE: Windows class recovery is more complete and tested than gcc class recovery, which is still -// in early stages of development. Gcc class data types are only recovered for classes without multiple or +// in early stages of development. Gcc class data types are only recovered for classes without // virtual inheritance but if the program contains DWARF, there will be some amount of data recovered // by the DWARF analyzer. // NOTE: For likely the best results, run this script on freshly analyzed programs. No testing has been @@ -65,6 +65,8 @@ import ghidra.app.services.Analyzer; import ghidra.app.services.GraphDisplayBroker; import ghidra.app.util.bin.format.dwarf4.next.DWARFFunctionImporter; import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram; +import ghidra.app.util.bin.format.dwarf4.next.sectionprovider.DWARFSectionProvider; +import ghidra.app.util.bin.format.dwarf4.next.sectionprovider.DWARFSectionProviderFactory; import ghidra.app.util.bin.format.pdb.PdbParserConstants; import ghidra.app.util.importer.MessageLog; import ghidra.framework.options.Options; @@ -74,6 +76,7 @@ import ghidra.program.model.data.*; import ghidra.program.model.listing.*; import ghidra.program.model.mem.MemoryBlock; import ghidra.service.graph.*; +import ghidra.util.WebColors; import ghidra.util.exception.CancelledException; import ghidra.util.exception.GraphException; import ghidra.util.task.TaskMonitor; @@ -117,6 +120,11 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { // edge between child and parent is orange if child inherits the parent virtually // edge between child and parent is lime green if child inherits the parent non-virtually private static final boolean GRAPH_CLASS_HIERARCHIES = false; + private static final String NO_INHERITANCE = "No Inheritance"; + private static final String SINGLE_INHERITANCE = "Single Inheritance"; + private static final String MULTIPLE_INHERITANCE = "Multiple Inheritance"; + private static final String VIRTUAL_INHERITANCE = "Virtual Inheritance"; + private static final String NON_VIRTUAL_INHERITANCE = "Non-virtual Inheritance"; // show shortened class template names in class structure field names private static final boolean USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS = true; @@ -134,23 +142,29 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { private static final String INDETERMINATE_BOOKMARK = "INDETERMINATE"; + // DO_NOT_REMOVE_REPLACED_CLASS_STRUCTURES // 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; + // REMOVE_EMPTY_REPLACED_CLASS_STRUCTURES // 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; + // REMOVE_ALL_REPLACED_CLASS_STRUCTURES // 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; + private static enum removeOption { + DO_NOT_REMOVE_REPLACED_CLASS_STRUCTURES, + REMOVE_EMPTY_REPLACED_CLASS_STRUCTURES, + REMOVE_ALL_REPLACED_CLASS_STRUCTURES + } // 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; + removeOption replacedClassStructuresOption = + removeOption.DO_NOT_REMOVE_REPLACED_CLASS_STRUCTURES; boolean programHasRTTIApplied = false; boolean hasDebugSymbols; @@ -178,16 +192,14 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { return; } - if (isWindows()) { hasDebugSymbols = isPDBLoadedInProgram(); nameVfunctions = !hasDebugSymbols; - 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); + 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()) { @@ -204,11 +216,10 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { return; } nameVfunctions = !hasDebugSymbols; - 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); + 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 { println("This script will not work on this program type"); @@ -281,7 +292,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { getNumberOfConstructorsOrDestructors(recoveredClasses) + " class member functions to assign."); - if (!hasDebugSymbols) { if (BOOKMARK_FOUND_FUNCTIONS) { @@ -301,23 +311,32 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { showGraph(graph); } - if (replacedClassStructuresOption == REMOVE_EMPTY_REPLACED_CLASS_STRUCTURES) { + if (replacedClassStructuresOption == removeOption.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) { + if (replacedClassStructuresOption == removeOption.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(); + } private boolean hasDwarf() { - return DWARFProgram.isDWARF(currentProgram); + if (DWARFProgram.isDWARF(currentProgram)) { + DWARFSectionProvider dsp = + DWARFSectionProviderFactory.createSectionProviderFor(currentProgram, monitor); + if (dsp == null) { + return false; + } + dsp.close(); + return true; + } + return false; } /** @@ -331,8 +350,10 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { private boolean isDwarfLoadedInProgram() { - return DWARFFunctionImporter.hasDWARFProgModule(currentProgram, - DWARFProgram.DWARF_ROOT_NAME); + Options options = currentProgram.getOptions(Program.PROGRAM_INFO); + + return (DWARFFunctionImporter.hasDWARFProgModule(currentProgram, + DWARFProgram.DWARF_ROOT_NAME) || options.getBoolean("DWARF Loaded", false)); } public String validate() { @@ -392,7 +413,15 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { private AttributedGraph createGraph(List recoveredClasses) throws CancelledException { - AttributedGraph g = new AttributedGraph("Test Graph", new EmptyGraphType()); + GraphType graphType = + new GraphTypeBuilder("Class Hierarchy Graph").vertexType(NO_INHERITANCE) + .vertexType(SINGLE_INHERITANCE) + .vertexType(MULTIPLE_INHERITANCE) + .edgeType(NON_VIRTUAL_INHERITANCE) + .edgeType(VIRTUAL_INHERITANCE) + .build(); + + AttributedGraph g = new AttributedGraph("Recovered Classes Graph", graphType); Iterator recoveredClassIterator = recoveredClasses.iterator(); while (recoveredClassIterator.hasNext()) { @@ -408,7 +437,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { // no parent = blue vertex if (classHierarchyMap.isEmpty()) { - classVertex.setAttribute("Color", "Blue"); + classVertex.setVertexType(NO_INHERITANCE); classVertex.setDescription(recoveredClass.getClassPath().getPath()); continue; } @@ -417,11 +446,11 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { // single parent = green vertex if (parents.size() == 1) { - classVertex.setAttribute("Color", "Green"); + classVertex.setVertexType(SINGLE_INHERITANCE); } // multiple parents = red vertex else { - classVertex.setAttribute("Color", "Red"); + classVertex.setVertexType(MULTIPLE_INHERITANCE); } classVertex.setDescription(recoveredClass.getClassPath().getPath()); @@ -448,9 +477,12 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { // edge between child and parent is orange if child inherits the parent virtually if (isVirtualParent) { - edge.setAttribute("Color", "Orange"); + edge.setEdgeType(VIRTUAL_INHERITANCE); } - // else edge between child and parent is lime green if child inherits the parent non-virtually + else { + edge.setEdgeType(NON_VIRTUAL_INHERITANCE); + } + } } @@ -471,7 +503,20 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { GraphDisplayBroker broker = tool.getService(GraphDisplayBroker.class); GraphDisplayProvider service = broker.getGraphDisplayProvider("Default Graph Display"); display = service.getGraphDisplay(false, TaskMonitor.DUMMY); - display.setGraph(graph, "test graph", false, TaskMonitor.DUMMY); + + GraphDisplayOptions graphOptions = new GraphDisplayOptionsBuilder(graph.getGraphType()) + .vertex(NO_INHERITANCE, VertexShape.RECTANGLE, WebColors.BLUE) + .vertex(SINGLE_INHERITANCE, VertexShape.RECTANGLE, WebColors.GREEN) + .vertex(MULTIPLE_INHERITANCE, VertexShape.RECTANGLE, WebColors.RED) + .edge(NON_VIRTUAL_INHERITANCE, WebColors.LIME_GREEN) + .edge(VIRTUAL_INHERITANCE, WebColors.ORANGE) + .defaultVertexColor(WebColors.PURPLE) + .defaultEdgeColor(WebColors.PURPLE) + .defaultLayoutAlgorithm("Compact Hierarchical") + .build(); + + display.setGraph(graph, graphOptions, + "Recovered Classes Graph", false, TaskMonitor.DUMMY); } /** diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/ExtraScriptUtils.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/ExtraScriptUtils.java index 150c8696b6..9f2e10ff17 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/ExtraScriptUtils.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/ExtraScriptUtils.java @@ -1045,8 +1045,10 @@ public class ExtraScriptUtils extends FlatProgramAPI { * @param parent parent CategoryPath * @param categoryName name of the new category in the parent path * @return CategoryPath for new categoryName + * @throws CancelledException if cancelled */ - public CategoryPath createDataTypeCategoryPath(CategoryPath parent, String categoryName) { + public CategoryPath createDataTypeCategoryPath(CategoryPath parent, String categoryName) + throws CancelledException { CategoryPath dataTypePath; @@ -1070,12 +1072,8 @@ public class ExtraScriptUtils extends FlatProgramAPI { int index = 0; String newCategoryName = new String(); while (index < categoryName.length()) { - try { - monitor.checkCanceled(); - } - catch (CancelledException e) { - return null; - } + + monitor.checkCanceled(); if (categoryName.substring(index).startsWith("::") && !insideBrackets) { newCategoryName = newCategoryName.concat("/"); diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIClassRecoverer.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIClassRecoverer.java index 408765ac17..4916548b85 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIClassRecoverer.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIClassRecoverer.java @@ -44,7 +44,7 @@ public class RTTIClassRecoverer extends RecoveredClassUtils { RTTIClassRecoverer(Program program, ProgramLocation location, PluginTool tool, FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates, boolean nameVfunctions, boolean hasDebugSymbols, boolean replaceClassStructures, - TaskMonitor monitor) { + TaskMonitor monitor) throws Exception { super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions, replaceClassStructures, @@ -76,7 +76,7 @@ public class RTTIClassRecoverer extends RecoveredClassUtils { return dataTypeManager; } - public boolean containsRTTI() throws CancelledException { + public boolean containsRTTI() throws CancelledException, InvalidInputException { return true; } @@ -104,12 +104,12 @@ public class RTTIClassRecoverer extends RecoveredClassUtils { - public void fixUpProgram() { + public void fixUpProgram() throws CancelledException, Exception { return; } - public List createRecoveredClasses() { + public List createRecoveredClasses() throws Exception { return new ArrayList(); } @@ -121,10 +121,10 @@ public class RTTIClassRecoverer extends RecoveredClassUtils { * Method to promote the namespace is a class namespace. * @param namespace the namespace for the vftable * @return true if namespace is (now) a class namespace or false if it could not be promoted. + * @throws InvalidInputException if namespace was contained in function and could not be promoted */ - public Namespace promoteToClassNamespace(Namespace namespace) { + public Namespace promoteToClassNamespace(Namespace namespace) throws InvalidInputException { - try { Namespace newClass = NamespaceUtils.convertNamespaceToClass(namespace); SymbolType symbolType = newClass.getSymbol().getSymbolType(); @@ -134,13 +134,6 @@ public class RTTIClassRecoverer extends RecoveredClassUtils { Msg.debug(this, "Could not promote " + namespace.getName() + " to a class namespace"); return null; - } - catch (InvalidInputException e) { - - Msg.debug(this, "Could not promote " + namespace.getName() + - " to a class namespace because " + e.getMessage()); - return null; - } } @@ -221,7 +214,7 @@ public class RTTIClassRecoverer extends RecoveredClassUtils { Structure existingClassStructure = (Structure) dataTypeManager.getDataType(dataTypePath, dataTypeName); - if (!existingClassStructure.isNotYetDefined()) { + if (existingClassStructure != null && !existingClassStructure.isNotYetDefined()) { recoveredClass.addExistingClassStructure(existingClassStructure); break; } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java index a678e60417..445a67e0a6 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java @@ -74,18 +74,16 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { public RTTIGccClassRecoverer(Program program, ProgramLocation location, PluginTool tool, FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates, boolean nameVfunctions, boolean isDwarfLoaded, boolean replaceExistingClassStructures, - TaskMonitor monitor) { + TaskMonitor monitor) throws Exception { super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions, - replaceExistingClassStructures, - isDwarfLoaded, - monitor); + replaceExistingClassStructures, isDwarfLoaded, monitor); this.isDwarfLoaded = isDwarfLoaded; this.replaceClassStructs = replaceExistingClassStructures; } @Override - public boolean containsRTTI() throws CancelledException { + public boolean containsRTTI() throws CancelledException, InvalidInputException { if (!hasSpecialVtable()) { return false; @@ -103,44 +101,33 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } @Override - public List createRecoveredClasses() { + public List createRecoveredClasses() throws CancelledException, Exception { - try { - - processGccRTTI(); - if (recoveredClasses == null) { - Msg.debug(this, "Could not recover gcc rtti classes"); - return null; - } - - createCalledFunctionMap(recoveredClasses); - - createClassHierarchyListAndMapForGcc(); - - if (isDwarfLoaded) { - retrieveExistingClassStructures(recoveredClasses); - assignConstructorsAndDestructorsUsingExistingName(recoveredClasses); - } - else { - processConstructorAndDestructors(); - } - - createVftableOrderMap(recoveredClasses); - - figureOutClassDataMembers(recoveredClasses); - - createAndApplyClassStructures(); - - return recoveredClasses; - } - catch (CancelledException e) { - e.printStackTrace(); + processGccRTTI(); + if (recoveredClasses == null) { + Msg.debug(this, "Could not recover gcc rtti classes"); return null; } - catch (Exception e) { - e.printStackTrace(); - return null; + + createCalledFunctionMap(recoveredClasses); + + createClassHierarchyListAndMapForGcc(); + + if (isDwarfLoaded) { + retrieveExistingClassStructures(recoveredClasses); + assignConstructorsAndDestructorsUsingExistingName(recoveredClasses); } + else { + processConstructorAndDestructors(); + } + + createVftableOrderMap(recoveredClasses); + + figureOutClassDataMembers(recoveredClasses); + + createAndApplyClassStructures(); + + return recoveredClasses; } @@ -171,8 +158,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { byte[] maskBytes = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }; Address found = program.getMemory() - .findBytes(commentBlock.getStart(), - commentBlock.getEnd(), gccBytes, maskBytes, true, monitor); + .findBytes(commentBlock.getStart(), commentBlock.getEnd(), gccBytes, maskBytes, + true, monitor); if (found == null) { return false; } @@ -184,8 +171,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { * Method to check for at least one special RTTI vtable * @return true if the program has at least one special vtable, false if none * @throws CancelledException if cancelled + * @throws InvalidInputException if bad characters creating labels */ - private boolean hasSpecialVtable() throws CancelledException { + private boolean hasSpecialVtable() throws CancelledException, InvalidInputException { boolean hasSpecialVtable = createSpecialVtables(); return hasSpecialVtable; @@ -287,8 +275,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } - private void updateClassesWithParentsAndFlags(List typeinfoSymbols) - throws Exception { + private void updateClassesWithParentsAndFlags(List typeinfoSymbols) throws Exception { // add properties and parents to each class Iterator typeinfoIterator = typeinfoSymbols.iterator(); @@ -464,6 +451,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { while (vtableIterator.hasNext()) { + monitor.checkCanceled(); Symbol vtableSymbol = vtableIterator.next(); @@ -534,14 +522,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { throw new Exception("typeinfo has global namespace " + typeinfoAddress); } - try { - Symbol vtableSymbol = symbolTable.createLabel(vtableAddress, VTABLE_LABEL, - classNamespace, SourceType.ANALYSIS); - vtableSymbols.add(vtableSymbol); - } - catch (InvalidInputException e) { - continue; - } + Symbol vtableSymbol = symbolTable.createLabel(vtableAddress, VTABLE_LABEL, + classNamespace, SourceType.ANALYSIS); + vtableSymbols.add(vtableSymbol); api.setPlateComment(vtableAddress, "vtable for " + classNamespace.getName(true)); } @@ -631,16 +614,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { if (namespacesByPath.isEmpty()) { - try { - Namespace newNamespace = - NamespaceUtils.createNamespaceHierarchy(name, vtableNamespace, - program, SourceType.ANALYSIS); - return newNamespace; - } - catch (InvalidInputException e) { - e.printStackTrace(); - return null; - } + Namespace newNamespace = NamespaceUtils.createNamespaceHierarchy(name, vtableNamespace, + program, SourceType.ANALYSIS); + return newNamespace; + } if (namespacesByPath.size() == 1) { return namespacesByPath.get(0); @@ -684,8 +661,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // check direct refs to see if they are in undefined area or not in function byte[] bytes = ProgramMemoryUtil.getDirectAddressBytes(program, typeinfoAddress); - addByteSearchPattern(searcher, validTypeinfoRefs, typeinfoAddress, bytes, - monitor); + addByteSearchPattern(searcher, validTypeinfoRefs, typeinfoAddress, bytes, monitor); } searcher.search(program, searchSet, monitor); @@ -780,10 +756,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { * @param vtableNamespace the namespace of the given vtable * @param isPrimary true if the vtable is the primary one for the class * @param listOfAllVtables list of all vtables + * @throws CancelledException if cancelled */ private void processVtable(Address vtableAddress, Namespace vtableNamespace, boolean isPrimary, - List listOfAllVtables) - throws Exception { + List listOfAllVtables) throws CancelledException, Exception { // skip the special tables if (vtableAddress.equals(class_type_info_vtable) || @@ -818,13 +794,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { Data typeinfoPtr = api.getDataAt(typeinfoAddress); if (typeinfoPtr == null) { DataType nullPointer = dataTypeManager.getPointer(null); - try { - api.createData(typeinfoAddress, nullPointer); - } - catch (Exception e) { - Msg.debug(this, - "Could not create typeinfo pointer at " + typeinfoAddress.toString()); - } + + api.createData(typeinfoAddress, nullPointer); + } // if not already named a construction-vtable then check to see if it is one so it can @@ -850,33 +822,19 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { Namespace classNamespace = createConstructionNamespace(vtableSymbol, vttSymbolBeforeConstructionVtable); - try { - vtableSymbol.setNameAndNamespace("construction-vtable", - classNamespace, SourceType.ANALYSIS); - vtableNamespace = vtableSymbol.getParentNamespace(); - // label the subVTTaddress - symbolTable.createLabel(subVTTAddress, "subVTT_" + n, - vttSymbolBeforeConstructionVtable.getParentNamespace(), - SourceType.ANALYSIS); + vtableSymbol.setNameAndNamespace("construction-vtable", classNamespace, + SourceType.ANALYSIS); + vtableNamespace = vtableSymbol.getParentNamespace(); + // label the subVTTaddress + symbolTable.createLabel(subVTTAddress, "subVTT_" + n, + vttSymbolBeforeConstructionVtable.getParentNamespace(), + SourceType.ANALYSIS); - api.setPlateComment(vtableAddress, "construction vtable " + n + - " for class " + + api.setPlateComment(vtableAddress, + "construction vtable " + n + " for class " + vttSymbolBeforeConstructionVtable.getParentNamespace() - .getName( - true)); + .getName(true)); - } - catch (InvalidInputException e) { - Msg.debug(this, e.getMessage()); - continue; - } - catch (CircularDependencyException e) { - Msg.debug(this, e.getMessage()); - continue; - } - catch (DuplicateNameException e) { - continue; - } } } @@ -919,25 +877,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { vftableLabel = "internal_" + vftableLabel; } - try { - symbolTable.createLabel(possibleVftableAddress, vftableLabel, vtableNamespace, - SourceType.ANALYSIS); + symbolTable.createLabel(possibleVftableAddress, vftableLabel, vtableNamespace, + SourceType.ANALYSIS); - createVftableArray(possibleVftableAddress, numFunctionPointers); - } - catch (IllegalArgumentException e) { - Msg.debug(this, "Could not label vftable at " + possibleVftableAddress.toString()); - } - catch (InvalidInputException e) { - Msg.debug(this, "Could not label vftable at " + possibleVftableAddress.toString()); - } - catch (CancelledException e) { - return; - } - catch (AddressOutOfBoundsException e) { - Msg.debug(this, "Couldn't create vftable due to Address out of bounds issue"); - return; - } + createVftableArray(possibleVftableAddress, numFunctionPointers); // check for an internal vtable after the vftable and make a symbol there if there is one // will process them later @@ -1050,7 +993,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } private boolean createInternalVtable(Address possibleInternalVtableAddress, - Namespace vtableNamespace) throws CancelledException { + Namespace vtableNamespace) throws CancelledException, InvalidInputException, Exception { // check to see if it is a pointer and if so, it cannot be an internal vtable // as they contain at least one long Address pointer = getPointerToDefinedMemory(possibleInternalVtableAddress); @@ -1071,27 +1014,12 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { (possibleInternalVtableSymbol.getSource() == SourceType.DEFAULT && (isValidVtableStart(possibleInternalVtableAddress) || isValidVftableStart(possibleInternalVtableAddress)))) { - try { - symbolTable.createLabel(possibleInternalVtableAddress, - "internal_vtable_" + possibleInternalVtableAddress.toString(), vtableNamespace, - SourceType.ANALYSIS); - processVtable(possibleInternalVtableAddress, vtableNamespace, false, null); - return true; - } - catch (IllegalArgumentException e) { - Msg.debug(this, "Could not label internal vtable at " + - possibleInternalVtableAddress.toString()); - return true; // still created vtable, just couldn't name it - } - catch (InvalidInputException e) { - Msg.debug(this, "Could not label internal vtable at " + - possibleInternalVtableAddress.toString()); - return true; // still created vtable, just couldn't name it - } - catch (Exception e) { - e.printStackTrace(); - } + symbolTable.createLabel(possibleInternalVtableAddress, + "internal_vtable_" + possibleInternalVtableAddress.toString(), vtableNamespace, + SourceType.ANALYSIS); + processVtable(possibleInternalVtableAddress, vtableNamespace, false, null); + return true; } return false; @@ -1102,8 +1030,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { * @param classNamespace the given namespace * @param address the address of the potential VTT table * @return true if a valid VTT has been discovered and label created + * @throws Exception if data creation results in an exception */ - private boolean createVTT(Namespace classNamespace, Address address) { + private boolean createVTT(Namespace classNamespace, Address address) throws Exception { // get pointer at address Address pointer = getPointerToDefinedMemory(address); @@ -1120,22 +1049,15 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } // if it is then create the VTT symbol and create pointer there - try { - symbolTable.createLabel(address, "VTT", classNamespace, SourceType.ANALYSIS); - } - catch (IllegalArgumentException e) { - Msg.debug(this, "Could not label VTT at " + address.toString()); - } - catch (InvalidInputException e) { - Msg.debug(this, "Could not label VTT at " + address.toString()); - } + + symbolTable.createLabel(address, "VTT", classNamespace, SourceType.ANALYSIS); DataType nullPointer = dataTypeManager.getPointer(null); try { api.createData(pointer, nullPointer); } catch (Exception e) { - // already data there + // already data there so don't try and overwrite it } api.setPlateComment(address, "VTT for " + classNamespace.getName(true)); @@ -1144,7 +1066,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } private Data createVftableArray(Address vftableAddress, int numFunctionPointers) - throws CancelledException, AddressOutOfBoundsException { + throws Exception { api.clearListing(vftableAddress, vftableAddress.add((numFunctionPointers * defaultPointerSize - 1))); @@ -1152,14 +1074,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { DataType pointerDataType = dataTypeManager.getPointer(null); ArrayDataType vftableArrayDataType = new ArrayDataType(pointerDataType, numFunctionPointers, defaultPointerSize); - try { - Data vftableArrayData = api.createData(vftableAddress, vftableArrayDataType); - return vftableArrayData; - } - catch (Exception e) { - return null; - } + Data vftableArrayData = api.createData(vftableAddress, vftableArrayDataType); + return vftableArrayData; } /** @@ -1349,35 +1266,25 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { * @param vtableAddress the given special vtable address * @return the address of the typeinfo in the vtable if replace was successful, null otherwise * @throws CancelledException if cancelled + * @throws InvalidInputException if bad characters when creating label */ - private Address createSpecialVtable(Address vtableAddress) throws CancelledException { + private Address createSpecialVtable(Address vtableAddress) + throws CancelledException, InvalidInputException { Symbol vtableSymbol = symbolTable.getPrimarySymbol(vtableAddress); api.clearListing(vtableAddress); - try { - int vtableLongs = createVtableLongs(vtableAddress); - if (vtableLongs > 0) { + int vtableLongs = createVtableLongs(vtableAddress); - Address typeinfoAddress = vtableAddress.add(vtableLongs * defaultPointerSize); - symbolTable.createLabel(typeinfoAddress, "typeinfo", - vtableSymbol.getParentNamespace(), SourceType.ANALYSIS); - return typeinfoAddress; - } - return null; - } + if (vtableLongs > 0) { - catch (AddressOutOfBoundsException e) { - return null; + Address typeinfoAddress = vtableAddress.add(vtableLongs * defaultPointerSize); + symbolTable.createLabel(typeinfoAddress, "typeinfo", vtableSymbol.getParentNamespace(), + SourceType.ANALYSIS); + return typeinfoAddress; } - catch (IllegalArgumentException e) { - return null; - } - catch (InvalidInputException e) { - return null; - } - + return null; } /** @@ -1409,7 +1316,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { api.createData(address, pointer); Address referencedAddress = extraUtils.getSingleReferencedAddress(address); - // if it isn't valid, clear what we just created and increment to offset so + // if it isn't a valid pointer, clear what we just created and increment to offset so // the next can be checked if (referencedAddress == null || !programAddressSet.contains(referencedAddress)) { api.clearListing(address); @@ -1422,6 +1329,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { return numLongs; } } + // if bump into existing data return the number found so far catch (Exception e) { return numLongs; } @@ -1534,20 +1442,13 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } private Data applyTypeinfoStructure(Structure typeInfoStructure, Address typeinfoAddress) - throws CancelledException, AddressOutOfBoundsException { + throws CancelledException, AddressOutOfBoundsException, Exception { api.clearListing(typeinfoAddress, typeinfoAddress.add(typeInfoStructure.getLength() - 1)); Data newStructure; - try { - newStructure = api.createData(typeinfoAddress, typeInfoStructure); - } - catch (Exception e) { - newStructure = null; - } - if (newStructure == null) { - Msg.debug(this, - "Could not create " + typeInfoStructure.getName() + " at " + typeinfoAddress); - } + + newStructure = api.createData(typeinfoAddress, typeInfoStructure); + return newStructure; } @@ -1560,14 +1461,14 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { try { numBases = api.getInt(typeinfoAddress.add(offsetOfNumBases)); } + // if there isn't enough memory to get the int then return null catch (MemoryAccessException | AddressOutOfBoundsException e) { return null; } // get or create the vmiClassTypeInfoStruct - Structure vmiClassTypeinfoStructure = - (Structure) dataTypeManager.getDataType(classDataTypesCategoryPath, - VMI_CLASS_TYPE_INFO_STRUCTURE + numBases); + Structure vmiClassTypeinfoStructure = (Structure) dataTypeManager + .getDataType(classDataTypesCategoryPath, VMI_CLASS_TYPE_INFO_STRUCTURE + numBases); if (vmiClassTypeinfoStructure == null) { vmiClassTypeinfoStructure = createVmiClassTypeInfoStructure(baseClassTypeInfoStructure, numBases); @@ -1575,7 +1476,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { return vmiClassTypeinfoStructure; } - private Symbol createDemangledTypeinfoSymbol(Address typeinfoAddress) { + private Symbol createDemangledTypeinfoSymbol(Address typeinfoAddress) + throws DuplicateNameException, InvalidInputException { String mangledTypeinfo = getTypeinfoName(typeinfoAddress); if (mangledTypeinfo == null) { @@ -1614,25 +1516,14 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } // create the new typeinfo symbol in the demangled namespace - try { - Symbol newSymbol = symbolTable.createLabel(typeinfoAddress, "typeinfo", classNamespace, - SourceType.ANALYSIS); - return newSymbol; - } - catch (InvalidInputException e) { - Msg.error(this, - typeinfoAddress.toString() + " invalid input exception " + e.getMessage()); - return null; - } - catch (IllegalArgumentException e) { - Msg.debug(this, - typeinfoAddress.toString() + " illegal argument exception " + e.getMessage()); - return null; - } + Symbol newSymbol = symbolTable.createLabel(typeinfoAddress, "typeinfo", classNamespace, + SourceType.ANALYSIS); + return newSymbol; } - private Namespace createTypeinfoClassNamespace(String namespaceString) { + private Namespace createTypeinfoClassNamespace(String namespaceString) + throws DuplicateNameException, InvalidInputException { int indexOfColons = namespaceString.indexOf("::"); Namespace namespace = globalNamespace; @@ -1659,20 +1550,14 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { return classNamespace; } - private Namespace getOrCreateNamespace(String namespaceName, Namespace parentNamespace) { + private Namespace getOrCreateNamespace(String namespaceName, Namespace parentNamespace) + throws DuplicateNameException, InvalidInputException { Namespace namespace = symbolTable.getNamespace(namespaceName, parentNamespace); if (namespace == null) { - try { - namespace = symbolTable.createNameSpace(parentNamespace, namespaceName, - SourceType.ANALYSIS); - } - catch (DuplicateNameException e) { - // shouldn't happen since it only gets here if the symbol didn't exist in the first place - } - catch (InvalidInputException e) { - return null; - } + + namespace = + symbolTable.createNameSpace(parentNamespace, namespaceName, SourceType.ANALYSIS); } return namespace; } @@ -1710,12 +1595,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { StringDataType sdt = new StringDataType(); String str; - try { - str = (String) sdt.getValue(buf, sdt.getDefaultSettings(), stringLen); - } - catch (AddressOutOfBoundsException e) { - return null; - } + + str = (String) sdt.getValue(buf, sdt.getDefaultSettings(), stringLen); + return str; } @@ -1814,26 +1696,37 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { return false; } + /** + * Get the references to the special type infos that exist in the current program. + * @return the references to the special type infos that exist in the current program + * @throws CancelledException if cancelled + */ private List
getTypeinfoAddressesUsingSpecialTypeinfos() throws CancelledException { List
specialTypeinfoRefs = new ArrayList
(); - Reference[] refsToClassTypeinfo = api.getReferencesTo(class_type_info); - for (Reference ref : refsToClassTypeinfo) { - monitor.checkCanceled(); - specialTypeinfoRefs.add(ref.getFromAddress()); + if (class_type_info != null) { + Reference[] refsToClassTypeinfo = api.getReferencesTo(class_type_info); + for (Reference ref : refsToClassTypeinfo) { + monitor.checkCanceled(); + specialTypeinfoRefs.add(ref.getFromAddress()); + } } - Reference[] refsToSiClassTypeinfo = api.getReferencesTo(si_class_type_info); - for (Reference ref : refsToSiClassTypeinfo) { - monitor.checkCanceled(); - specialTypeinfoRefs.add(ref.getFromAddress()); + if (si_class_type_info != null) { + Reference[] refsToSiClassTypeinfo = api.getReferencesTo(si_class_type_info); + for (Reference ref : refsToSiClassTypeinfo) { + monitor.checkCanceled(); + specialTypeinfoRefs.add(ref.getFromAddress()); + } } - Reference[] refsToVmiClassTypeinfo = api.getReferencesTo(vmi_class_type_info); - for (Reference ref : refsToVmiClassTypeinfo) { - monitor.checkCanceled(); - specialTypeinfoRefs.add(ref.getFromAddress()); + if (vmi_class_type_info != null) { + Reference[] refsToVmiClassTypeinfo = api.getReferencesTo(vmi_class_type_info); + for (Reference ref : refsToVmiClassTypeinfo) { + monitor.checkCanceled(); + specialTypeinfoRefs.add(ref.getFromAddress()); + } } return specialTypeinfoRefs; @@ -2153,8 +2046,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { //virtual base offset for the virtual base referenced (negative). long offset = (publicVirtualOffsetFlag & offsetMask) >> 8; - Msg.debug(this, "typeinfo " + typeinfoAddress + " base [" + i + "] isVirtual = " + - isVirtual + " isPublic = " + isPublic + " offset = " + offset); + if (DEBUG) { + Msg.debug(this, "typeinfo " + typeinfoAddress + " base [" + i + "] isVirtual = " + + isVirtual + " isPublic = " + isPublic + " offset = " + offset); + } // add order to parent and parent offset orderToParentMap.put(i, parentClass); @@ -2232,8 +2127,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { * correct data types. Also creates a type info symbol at the correct offset in the table. * @return true if all found tables have a typeinfo symbol created successfully * @throws CancelledException if cancelled + * @throws InvalidInputException if bad characters creating labels */ - private boolean createSpecialVtables() throws CancelledException { + private boolean createSpecialVtables() throws CancelledException, InvalidInputException { class_type_info_vtable = findSpecialVtable("__cxxabiv1", "__class_type_info"); class_type_info = null; @@ -2517,8 +2413,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { * Use information from RTTI Base class Arrays to create class hierarchy lists and maps * @throws CancelledException if cancelled */ - private void createClassHierarchyListAndMapForGcc() - throws CancelledException, Exception { + private void createClassHierarchyListAndMapForGcc() throws CancelledException, Exception { Iterator recoveredClassIterator = recoveredClasses.iterator(); while (recoveredClassIterator.hasNext()) { @@ -2683,22 +2578,20 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { * address * @param start the starting address * @param end the ending address + * @throws CancelledException if cancelled + * @throws Exception if data has conflict when created */ - private void createLongs(Address start, Address end) { + private void createLongs(Address start, Address end) throws CancelledException, Exception { LongDataType longDT = new LongDataType(); int offset = 0; Address address = start; while (address != null && !address.equals(end)) { - try { - api.clearListing(address); - api.createData(address, longDT); - offset += defaultPointerSize; - address = getAddress(start, offset); - } - catch (Exception e) { - return; - } + + api.clearListing(address, address.add(defaultPointerSize - 1)); + api.createData(address, longDT); + offset += defaultPointerSize; + address = getAddress(start, offset); } } @@ -2868,9 +2761,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // can't handle creating class data types for classes with virtual parents yet if (recoveredClass.inheritsVirtualAncestor()) { if (DEBUG) { - Msg.debug(this, "Cannot create class data type for " + - recoveredClass.getClassNamespace().getName(true) + - " because it has virtual ancestors and we don't yet handle that use case."); + Msg.debug(this, + "Cannot create class data type for " + + recoveredClass.getClassNamespace().getName(true) + + " because it has virtual ancestors and we don't yet handle that use case."); } return; } @@ -2901,27 +2795,23 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // and class member data structure 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, classStruct); + // Now that we have a class data type + // name constructor and destructor functions and put into the class namespace + addConstructorsToClassNamespace(recoveredClass, classStruct); + addDestructorsToClassNamespace(recoveredClass, classStruct); + //TODO: // addNonThisDestructorsToClassNamespace(recoveredClass); // addVbaseDestructorsToClassNamespace(recoveredClass); // addVbtableToClassNamespace(recoveredClass); -// + //TODO: // // 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, classStruct); - } + // 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 diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java index ddadec4088..86e25347e8 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java @@ -70,7 +70,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { public RTTIWindowsClassRecoverer(Program program, ProgramLocation location, PluginTool tool, FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates, boolean nameVFunctions, boolean isPDBLoaded, boolean replaceClassStructures, - TaskMonitor monitor) throws CancelledException { + TaskMonitor monitor) throws Exception { super(program, location, tool, api, createBookmarks, useShortTemplates, nameVFunctions, isPDBLoaded, replaceClassStructures, monitor); @@ -98,121 +98,98 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { } @Override - public void fixUpProgram() { + public void fixUpProgram() throws CancelledException, Exception { if (ghidraVersion.compareTo("10.0") < 0) { - try { - fixUpRttiAnalysis(); - } - catch (Exception e) { - e.printStackTrace(); - } - } + fixUpRttiAnalysis(); + + } // if there are undefined areas that reference vftables attempt to create functions // containing them - List vftableSymbols; - try { - vftableSymbols = getListOfVftableSymbols(); - createMissingFunctions(vftableSymbols); - } - catch (CancelledException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + List vftableSymbols = getListOfVftableSymbols(); + + createMissingFunctions(vftableSymbols); return; } @Override - public List createRecoveredClasses() { + public List createRecoveredClasses() throws Exception { List vftableSymbols; - try { - vftableSymbols = getListOfVftableSymbols(); - List recoveredClasses = - recoverClassesFromClassHierarchyDescriptors(vftableSymbols); + vftableSymbols = getListOfVftableSymbols(); - determineVftableOffsetsfromRTTI(recoveredClasses); + List recoveredClasses = + recoverClassesFromClassHierarchyDescriptors(vftableSymbols); - // If no new classes have been recovered, no need to continue. Return out of script. - if (recoveredClasses.isEmpty()) { + determineVftableOffsetsfromRTTI(recoveredClasses); - return recoveredClasses; - } - - createCalledFunctionMap(recoveredClasses); - - // figure out class hierarchies using either RTTI or vftable refs - - monitor.setMessage("Assigning class inheritance and hierarchies"); - assignClassInheritanceAndHierarchies(recoveredClasses); - - // Since PDB has applied so much information, use it to figure out the class member data 4 - // items (if it has them) and the constructors and destructors. - if (isPDBLoaded) { - monitor.setMessage( - "Attempting to use pdb to assign class hierarchies and extend known pdb data " + - "type information ..."); - - retrieveExistingClassStructures(recoveredClasses); - - // assign constructors and destructors based on name - assignConstructorsAndDestructorsUsingExistingName(recoveredClasses); - } - // otherwise figure everything out from scratch - else { - monitor.setMessage("Figuring out class method types"); - // println( -// "Figuring out class method types (constructor, destructor, inline constructor, " + -// "inline destructor, deleting destructor, clone) ..."); - processConstructorAndDestructors(recoveredClasses); - - } - - // create order of vftable in constructor map for each class that has a constructor so far - createVftableOrderMap(recoveredClasses); - - determineParentClassInfoFromBaseClassArray(recoveredClasses); - - assignParentClassToVftables(recoveredClasses); - - // using all the information found above, create the class structures, add the constructor, - // destructor, vfunctions to class which finds the appropriate class structure and assigns - // to "this" param - //println("Creating class data types and applying class structures..."); - monitor.setMessage("Creating class data types and applying class structures"); - figureOutClassDataMembers(recoveredClasses); - - if (USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS) { - extraUtils.createShortenedTemplateNamesForClasses(recoveredClasses); - } - - createAndApplyClassStructures(recoveredClasses); - - if (!isPDBLoaded) { - // create better vftable labels for multi vftable classes - updateMultiVftableLabels(recoveredClasses); - //println("Removing erroneous FID namespaces and corresponding class data types"); - removeEmptyClassesAndStructures(); - } + // If no new classes have been recovered, no need to continue. Return out of script. + if (recoveredClasses.isEmpty()) { return recoveredClasses; } - catch (CancelledException e) { - e.printStackTrace(); - return null; + + createCalledFunctionMap(recoveredClasses); + + // figure out class hierarchies using either RTTI or vftable refs + + monitor.setMessage("Assigning class inheritance and hierarchies"); + assignClassInheritanceAndHierarchies(recoveredClasses); + + // Since PDB has applied so much information, use it to figure out the class member data 4 + // items (if it has them) and the constructors and destructors. + if (isPDBLoaded) { + monitor.setMessage( + "Attempting to use pdb to assign class hierarchies and extend known pdb data " + + "type information ..."); + + retrieveExistingClassStructures(recoveredClasses); + + // assign constructors and destructors based on name + assignConstructorsAndDestructorsUsingExistingName(recoveredClasses); } - catch (Exception e) { - e.printStackTrace(); - return null; + // otherwise figure everything out from scratch + else { + monitor.setMessage("Figuring out class method types"); + // println( +// "Figuring out class method types (constructor, destructor, inline constructor, " + +// "inline destructor, deleting destructor, clone) ..."); + processConstructorAndDestructors(recoveredClasses); + } + // create order of vftable in constructor map for each class that has a constructor so far + createVftableOrderMap(recoveredClasses); + + determineParentClassInfoFromBaseClassArray(recoveredClasses); + + assignParentClassToVftables(recoveredClasses); + + // using all the information found above, create the class structures, add the constructor, + // destructor, vfunctions to class which finds the appropriate class structure and assigns + // to "this" param + //println("Creating class data types and applying class structures..."); + monitor.setMessage("Creating class data types and applying class structures"); + figureOutClassDataMembers(recoveredClasses); + + if (USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS) { + extraUtils.createShortenedTemplateNamesForClasses(recoveredClasses); + } + + createAndApplyClassStructures(recoveredClasses); + + if (!isPDBLoaded) { + // create better vftable labels for multi vftable classes + updateMultiVftableLabels(recoveredClasses); + //println("Removing erroneous FID namespaces and corresponding class data types"); + removeEmptyClassesAndStructures(); + } + + return recoveredClasses; + } private boolean isVisualStudioOrClangPe() { @@ -351,7 +328,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { continue; } - //println("Cannot create RTTI_CompleteObjectLocator at " + symbol.getAddress()); + Msg.debug(this, "Cannot create RTTI_CompleteObjectLocator at " + symbol.getAddress()); } return completeObjectLocatorSymbols; @@ -417,7 +394,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { continue; } - //println("Cannot create RTTI_Base_Class_Descriptor at " + symbol.getAddress()); + Msg.debug(this, "Cannot create RTTI_Base_Class_Descriptor at " + symbol.getAddress()); } return baseClassDescriptorSymbols; @@ -661,8 +638,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { continue; } -// println("Failed to create a baseClassDescArray structure at " + -// baseClassArrayAddress.toString()); + Msg.debug(this, "Failed to create a baseClassDescArray structure at " + + baseClassArrayAddress.toString()); } return baseClassArrayAddresses; } @@ -736,13 +713,14 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { Namespace classNamespace = completeObjectLocatorSymbol.getParentNamespace(); if (classNamespace.equals(globalNamespace)) { - //println("no class namespace for " + completeObjectLocatorAddress.toString()); + Msg.debug(this, + "No class namespace for " + completeObjectLocatorAddress.toString()); continue; } Reference[] referencesTo = extraUtils.getReferencesTo(completeObjectLocatorAddress); if (referencesTo.length == 0) { - //println("no refs to " + completeObjectLocatorAddress.toString()); + Msg.debug(this, "No refs to " + completeObjectLocatorAddress.toString()); continue; } @@ -995,7 +973,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { * @throws Exception when cancelled */ private void determineVftableOffsetsfromRTTI(List recoveredClasses) - throws Exception { + throws AddressOutOfBoundsException, Exception { PointerDataType pointerDataType = new PointerDataType(); @@ -1020,22 +998,16 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { Address colAddress = extraUtils.getReferencedAddress(ptrToColAddress, false); if (colAddress == null) { -// println(recoveredClass.getName() + " couldn't get referenced col from " + -// ptrToColAddress.toString()); + Msg.debug(this, recoveredClass.getName() + + " couldn't get referenced col from " + ptrToColAddress.toString()); continue; } - try { - Address addressOfOffset = colAddress.add(4); + Address addressOfOffset = colAddress.add(4); - int offset = extraUtils.getInt(addressOfOffset); + int offset = extraUtils.getInt(addressOfOffset); - recoveredClass.addClassOffsetToVftableMapping(offset, vftableAddress); - } - catch (AddressOutOfBoundsException e) { -// println(recoveredClass.getName() + "error getting offset at address " + -// colAddress.toString() + " + 4"); - } + recoveredClass.addClassOffsetToVftableMapping(offset, vftableAddress); } } @@ -1063,9 +1035,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { int inheritanceFlag = getClassInheritanceFlag(recoveredClass.getClassNamespace()); if (inheritanceFlag == NONE) { -// println( -// "Could not get inheritance attribute from class hierarchy structure for " + -// "class " + recoveredClass.getName()); + Msg.debug(this, + "Could not get inheritance attribute from class hierarchy structure for " + + "class " + recoveredClass.getName()); recoveredClassesIterator.remove(); continue; } @@ -1250,21 +1222,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { RTTI_CLASS_HIERARCHY_DESCRIPTOR_LABEL, classNamespace, false); if (symbols.size() >= 1) { - - try { - return (extraUtils.getInt(symbols.get(0).getAddress().add(4))); - } - catch (MemoryAccessException e) { -// println("Could not get class inheritance flag at address " + -// symbols.get(0).getAddress().toString()); - return NONE; - } - catch (AddressOutOfBoundsException e) { -// println("Could not get class inheritance flag at address " + -// symbols.get(0).getAddress().toString()); - return NONE; - } + return (extraUtils.getInt(symbols.get(0).getAddress().add(4))); } + return NONE; } @@ -1399,7 +1359,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { // this should never happen if (baseClassArray.size() != 1) { throw new Exception( - recoveredClass.getName() + " has more than one base class array"); + recoveredClass.getName() + " has more than one RTTI base class array"); } Address baseClassArrayAddress = baseClassArray.get(0).getAddress(); @@ -1407,7 +1367,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { if (!baseClassArrayData.isArray()) { throw new Exception( - recoveredClass.getName() + " base class array is not an array data type"); + recoveredClass.getName() + " RTTI base class array is not an array data type " + + baseClassArrayAddress.toString()); } @@ -2690,9 +2651,11 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { * @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 */ public Integer getSingleVirtualParentOffset(RecoveredClass recoveredClass) - throws CancelledException { + throws CancelledException, MemoryAccessException, AddressOutOfBoundsException { List virtualParentClasses = getVirtualParentClasses(recoveredClass); if (virtualParentClasses.size() != 1) { @@ -2706,7 +2669,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { } private Map getBaseClassOffsetMap(RecoveredClass recoveredClass) - throws CancelledException { + throws CancelledException, MemoryAccessException, AddressOutOfBoundsException { Map parentOffsetMap = new HashMap(); @@ -2727,52 +2690,39 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { continue; } - try { - RecoveredClass baseClass = - getClassFromBaseClassDescriptor(baseClassDescriptorAddress); - if (baseClass == null) { - // TODO: msg and return null - continue; - } - - // Continue if the class has mult inh but base class is not on the parent list - //TODO: possibly update to include all base classes - if (!recoveredClass.getParentList().contains(baseClass)) { - continue; - } - - int mdisp = api.getInt(baseClassDescriptorAddress.add(8)); - int pdisp = api.getInt(baseClassDescriptorAddress.add(12)); - int vdisp = api.getInt(baseClassDescriptorAddress.add(16)); - if (pdisp == -1) { - - baseClassOffset = mdisp; - } - else { - // else need to fill in the virtually inherited ones - // get the offset of this base class in the class using the vbtable - Address vbtableAddress = recoveredClass.getVbtableAddress(); - if (vbtableAddress == null) { - Msg.error(this, - "Cannot retrieve vbtable address so cannot create base class offset map for class " + - recoveredClass.getName()); - return null; - } - - baseClassOffset = - api.getInt(recoveredClass.getVbtableAddress().add(vdisp)) + pdisp; - } - - parentOffsetMap.put(baseClass, baseClassOffset); - + RecoveredClass baseClass = getClassFromBaseClassDescriptor(baseClassDescriptorAddress); + if (baseClass == null) { + // TODO: return null? + Msg.debug(this, "Could not get base class from baseClassDescriptor " + + baseClassDescriptorAddress.toString()); + continue; } - catch (MemoryAccessException | AddressOutOfBoundsException e) { - Msg.error(this, - "Cannot create base class offset map for class " + recoveredClass.getName()); - return null; + // Continue if the class has mult inh but base class is not on the parent list + //TODO: possibly update to include all base classes + if (!recoveredClass.getParentList().contains(baseClass)) { + continue; } + int mdisp = api.getInt(baseClassDescriptorAddress.add(8)); + int pdisp = api.getInt(baseClassDescriptorAddress.add(12)); + int vdisp = api.getInt(baseClassDescriptorAddress.add(16)); + if (pdisp == -1) { + baseClassOffset = mdisp; + } + else { + // else need to fill in the virtually inherited ones + // get the offset of this base class in the class using the vbtable + Address vbtableAddress = recoveredClass.getVbtableAddress(); + if (vbtableAddress == null) { + Msg.error(this, + "Cannot retrieve vbtable address so cannot create base class offset map for class " + + recoveredClass.getName()); + return null; + } + baseClassOffset = api.getInt(recoveredClass.getVbtableAddress().add(vdisp)) + pdisp; + } + parentOffsetMap.put(baseClass, baseClassOffset); } return parentOffsetMap; } @@ -2885,9 +2835,11 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { * order to distinguish which base class the vftable is for. * @param recoveredClasses the list of RecoveredClass objects * @throws CancelledException if cancelled + * @throws InvalidInputException if bad chars trying to label + * @throws DuplicateNameException if duplicate name */ private void updateMultiVftableLabels(List recoveredClasses) - throws CancelledException { + throws CancelledException, DuplicateNameException, InvalidInputException { if (recoveredClasses.isEmpty()) { return; @@ -2914,19 +2866,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { if (!shortenedTemplateName.isBlank()) { baseClassName = shortenedTemplateName; } - try { - primarySymbol.setName("vftable_for_" + baseClassName, - primarySymbol.getSource()); - } - catch (DuplicateNameException e) { - // skip if it's already the correct name - } - catch (InvalidInputException e) { - Msg.debug(this, - "Could not create vftable_for_" + baseClassName + - " due to invalid input exeption at address " + - vftableAddress.toString()); - } + + primarySymbol.setName("vftable_for_" + baseClassName, + primarySymbol.getSource()); } } } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassUtils.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassUtils.java index 175292e794..d6cecc9c09 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassUtils.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassUtils.java @@ -148,7 +148,8 @@ public class RecoveredClassUtils { public RecoveredClassUtils(Program program, ProgramLocation location, PluginTool tool, FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates, - boolean nameVunctions, boolean replaceClassStructures, TaskMonitor monitor) { + boolean nameVunctions, boolean replaceClassStructures, TaskMonitor monitor) + throws Exception { this.monitor = monitor; this.program = program; @@ -551,13 +552,13 @@ public class RecoveredClassUtils { } /** - * Method to return reference to the class vftable in the given function + * Method to return the first reference to the class vftable in the given function * @param recoveredClass the given class * @param function the given function * @return the reference to the class vftable in the given function or null if there isn't one * @throws CancelledException if cancelled */ - public Address getClassVftableReference(RecoveredClass recoveredClass, + public Address getFirstClassVftableReference(RecoveredClass recoveredClass, Function function) throws CancelledException { List
vftableReferenceList = functionToVftableRefsMap.get(function); @@ -566,6 +567,8 @@ public class RecoveredClassUtils { return null; } + Collections.sort(vftableReferenceList); + Iterator
vftableRefs = vftableReferenceList.iterator(); while (vftableRefs.hasNext()) { monitor.checkCanceled(); @@ -589,39 +592,6 @@ public class RecoveredClassUtils { } - /** - * Method to return the vftable reference in the given function that corresponds to the given class - * @param function the given function - * @param recoveredClass the given class - * @return the vftableRef address in the given function that corresponds to the given class - * @throws CancelledException if cancelled - */ - public Address getClassVftableRefInFunction(Function function, RecoveredClass recoveredClass) - throws CancelledException { - - List
listOfClassRefsInFunction = - getSortedListOfAncestorRefsInFunction(function, recoveredClass); - - Iterator
iterator = listOfClassRefsInFunction.iterator(); - while (iterator.hasNext()) { - monitor.checkCanceled(); - Address classRef = iterator.next(); - Address vftableAddress = vftableRefToVftableMap.get(classRef); - - // skip the ones that aren't vftable refs - if (vftableAddress == null) { - continue; - } - - // return the first one that is a vftable ref to the given class - RecoveredClass vftableClass = vftableToClassMap.get(vftableAddress); - if (vftableClass.equals(recoveredClass)) { - return classRef; - } - } - return null; - } - /** * Method to get a sorted list of both vftable and call refs to ancestor classes of the given * class in the given function @@ -3389,7 +3359,7 @@ public class RecoveredClassUtils { replaceClassStructure(destructorFunction, className, classStruct); } - destructorFunction.setReturnType(DataType.VOID, SourceType.ANALYSIS); + destructorFunction.setReturnType(new VoidDataType(), SourceType.ANALYSIS); } } @@ -3445,7 +3415,7 @@ public class RecoveredClassUtils { classStruct); } - vbaseDestructorFunction.setReturnType(DataType.VOID, SourceType.ANALYSIS); + vbaseDestructorFunction.setReturnType(new VoidDataType(), SourceType.ANALYSIS); } } @@ -3635,7 +3605,9 @@ public class RecoveredClassUtils { return true; } - //TODO: decide whether to replace dwarf or not + if (categoryPath.contains("DWARF")) { + return true; + } // test to see if the data type is an empty structure with "PlaceHolder Class Structure" in // the description @@ -5146,25 +5118,12 @@ public class RecoveredClassUtils { while (inlinedDestructorIterator.hasNext()) { monitor.checkCanceled(); Function destructorFunction = inlinedDestructorIterator.next(); - Address classVftableRef = - getClassVftableRefInFunction(destructorFunction, recoveredClass); - - //TODO: use this one instead if testing pans out - Address otherWayRef = getClassVftableReference(recoveredClass, destructorFunction); + Address classVftableRef = getFirstClassVftableReference(recoveredClass, destructorFunction); if (classVftableRef == null) { continue; } - //TODO: remove after testing - if (!classVftableRef.equals(otherWayRef)) { - if (DEBUG) { - Msg.debug(this, recoveredClass.getName() + " function " + - destructorFunction.getEntryPoint().toString() + " first ref: " + - classVftableRef.toString() + " other way ref: " + otherWayRef.toString()); - } - } - String markupString = classNamespace.getName(true) + "::~" + className; api.setPreComment(classVftableRef, "inlined destructor: " + markupString); @@ -5189,24 +5148,11 @@ public class RecoveredClassUtils { Function functionContainingInline = functionsContainingInlineIterator.next(); Address classVftableRef = - getClassVftableRefInFunction(functionContainingInline, recoveredClass); - //TODO: use this one if testing more progs gives same results - Address otherWayRef = - getClassVftableReference(recoveredClass, functionContainingInline); + getFirstClassVftableReference(recoveredClass, functionContainingInline); if (classVftableRef == null) { continue; } - //TODO: remove after testing - if (!classVftableRef.equals(otherWayRef)) { - if (DEBUG) { - Msg.debug(this, - recoveredClass.getName() + " function " + - functionContainingInline.getEntryPoint().toString() + " first ref: " + - classVftableRef.toString() + " other way ref: " + - otherWayRef.toString()); - } - } String markupString = "inlined constructor or destructor (approx location) for " + classNamespace.getName(true); @@ -5419,22 +5365,11 @@ public class RecoveredClassUtils { // Type 4 inlined - inlined class c/d called from other than first function // either just vftable ref before operator delete or vftableref followed by parent call // before operator delete + Address vftableReference = getFirstClassVftableReference(recoveredClass, virtualFunction); - Address vftableReference = getClassVftableReference(recoveredClass, virtualFunction); - - //TODO remove after testing against prev method in more progs - Address otherWayRef = getClassVftableRefInFunction(virtualFunction, recoveredClass); if (vftableReference == null) { return; } - if (!vftableReference.equals(otherWayRef)) { - if (DEBUG) { - Msg.debug(this, recoveredClass.getName() + " function " + - virtualFunction.getEntryPoint().toString() + " first ref: " + - vftableReference.toString() + " other way ref (with ances): " + - otherWayRef.toString()); - } - } List possibleParentDestructors = getPossibleParentDestructors(virtualFunction); @@ -5725,43 +5660,6 @@ public class RecoveredClassUtils { } - private boolean isDataAtOffsetEquivalentToStructure(Structure outerStructure, - Structure innerStructure, int offset) { - - DataTypeComponent[] innerStructComponents = innerStructure.getDefinedComponents(); - for (DataTypeComponent innerComponent : innerStructComponents) { - int innerOffset = innerComponent.getOffset(); - - DataTypeComponent outerComponent = outerStructure.getComponentAt(offset + innerOffset); - if (outerComponent == null) { - return false; - } - - if (innerComponent.getFieldName().equals("vftablePtr")) { - - // if one is vftablePtr and other isn't - return false - if (!outerComponent.getFieldName().equals("vftablePtr")) { - return false; - } - - // if both are vftablePtrs they should both contain the innerStructure name (ie the class name) in - // the vftablePtr data type name (either _vftable_for_ or _vftable * - if (outerComponent.getDataType().getDisplayName().contains( - innerStructure.getName()) && - !innerComponent.getDataType().getDisplayName().contains( - innerStructure.getName())) { - return false; - } - continue; - } - - if (!innerComponent.getDataType().equals(outerComponent.getDataType())) { - return false; - } - } - return true; - } - /** * Method to determine if the given data type is the virtual parent class structure for the given class * @param recoveredClass the given class @@ -6552,7 +6450,7 @@ public class RecoveredClassUtils { if (!atexitCalledFunctions.contains(calledFunction)) { atexitCalledFunctions.add(calledFunction); } - calledFunction.setReturnType(DataType.VOID, SourceType.ANALYSIS); + calledFunction.setReturnType(new VoidDataType(), SourceType.ANALYSIS); } else { if (!atexitCalledFunctions.contains(calledFunction)) {