diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java b/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java index 09d7b29b26..5351d9f644 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java @@ -78,6 +78,7 @@ import ghidra.program.model.address.*; import ghidra.program.model.data.*; import ghidra.program.model.listing.*; import ghidra.program.model.mem.MemoryBlock; +import ghidra.program.util.GhidraProgramUtilities; import ghidra.service.graph.*; import ghidra.util.exception.CancelledException; import ghidra.util.exception.GraphException; @@ -85,6 +86,8 @@ import ghidra.util.task.TaskMonitor; public class RecoverClassesFromRTTIScript extends GhidraScript { + public static final String RTTI_FOUND_OPTION = "RTTI Found"; + // print c-like class definitions to the console private static final boolean PRINT_CLASS_DEFINITIONS = false; @@ -138,7 +141,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { private static final String INDETERMINATE_BOOKMARK = "INDETERMINATE"; - boolean programHasRTTIApplied = false; boolean hasDebugSymbols; boolean isGcc = false; boolean isWindows = false; @@ -166,6 +168,23 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { if (isWindows()) { + if (!isRttiAnalyzed()) { + println("Running the RTTIAnalyzer..."); + analysisMode = AnalysisMode.ENABLED; + runScript("RunRttiAnalyzerScript.java"); + analysisMode = AnalysisMode.SUSPENDED; + + if (!isRttiAnalyzed()) { + println("The RTTI Analyzer did not complete successfully."); + return; + } + + if (!hasRtti()) { + println("This program does not contain RTTI."); + return; + } + } + hasDebugSymbols = isPDBLoadedInProgram(); nameVfunctions = !hasDebugSymbols; recoverClassesFromRTTI = @@ -176,7 +195,8 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { else if (isGcc()) { boolean runGcc = askYesNo("GCC Class Recovery Still Under Development", - "I understand that gcc class recovery is still under development and my results will be incomplete but want to run this anyway."); + "I understand that gcc class recovery is still under development and my results " + + "will be incomplete but want to run this anyway."); if (!runGcc) { return; } @@ -187,7 +207,8 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { hasDebugSymbols = isDwarfLoadedInProgram(); if (hasDwarf() && !hasDebugSymbols) { println( - "The program contains DWARF but the DWARF analyzer has not been run. Please run the DWARF analyzer to get best results from this script."); + "The program contains DWARF but the DWARF analyzer has not been run. Please " + + "run the DWARF analyzer to get best results from this script."); return; } nameVfunctions = !hasDebugSymbols; @@ -203,7 +224,8 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { if (!recoverClassesFromRTTI.containsRTTI()) { println( - "This program does not appear to contain any processed RTTI information. Either it does not contain any or the RTTI Analyzer was not run."); + "This program does not appear to contain any processed RTTI information. Either " + + "it does not contain any or the RTTI Analyzer was not run."); return; } @@ -242,9 +264,8 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { "/" + RecoveredClassHelper.DTM_CLASS_DATA_FOLDER_NAME); if (FIXUP_PROGRAM) { - println( - "Checking for missing RTTI information and undefined constructor/destructor functions and creating if possible " + - "to find entry point..."); + println("Checking for missing RTTI information and undefined constructor/destructor " + + "functions and creating if possible " + "to find entry point..."); AddressSetView beforeScriptChanges = currentProgram.getChanges().getAddressSet(); analysisMode = AnalysisMode.ENABLED; @@ -334,6 +355,15 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { return ("There is no open program"); } + if (!GhidraProgramUtilities.isAnalyzedFlagSet(currentProgram)) { + return ("The program has not been analyzed. Please run auto-analysis and make sure " + + "the RTTI analzer is one of the analyzers enabled."); + } + + if (isRttiAnalyzed() && !hasRtti()) { + return ("This program does not contain RTTI."); + } + CategoryPath path = new CategoryPath(CategoryPath.ROOT, RecoveredClassHelper.DTM_CLASS_DATA_FOLDER_NAME); if (currentProgram.getDataTypeManager().containsCategory(path)) { @@ -341,7 +371,8 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { } if (!checkGhidraVersion()) { - return ("This script only works with Ghidra version 9.2, 9.2.2 and later. It does not work on Ghidra 9.2.1 or on versions prior to 9.2"); + return ("This script only works with Ghidra version 9.2, 9.2.2 and later. It does" + + " not work on Ghidra 9.2.1 or on versions prior to 9.2"); } if (!isGcc() && !isWindows()) { @@ -491,8 +522,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { .defaultLayoutAlgorithm("Compact Hierarchical") .build(); - display.setGraph(graph, graphOptions, - "Recovered Classes Graph", false, TaskMonitor.DUMMY); + display.setGraph(graph, graphOptions, "Recovered Classes Graph", false, TaskMonitor.DUMMY); } /** @@ -547,12 +577,10 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { return false; } - boolean isCompilerSpecGcc = - currentProgram.getCompilerSpec() - .getCompilerSpecID() - .getIdAsString() - .equalsIgnoreCase( - "gcc"); + boolean isCompilerSpecGcc = currentProgram.getCompilerSpec() + .getCompilerSpecID() + .getIdAsString() + .equalsIgnoreCase("gcc"); if (isCompilerSpecGcc) { return true; } @@ -571,8 +599,8 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { byte[] maskBytes = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }; Address found = currentProgram.getMemory() - .findBytes(commentBlock.getStart(), - commentBlock.getEnd(), gccBytes, maskBytes, true, monitor); + .findBytes(commentBlock.getStart(), commentBlock.getEnd(), gccBytes, maskBytes, + true, monitor); if (found == null) { isGcc = false; } @@ -607,19 +635,15 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { List allClassDestructors = recoverClassesFromRTTI.getAllClassDestructors(recoveredClass); - List commonFunctions1 = - allClassConstructors.stream() - .distinct() - .filter(allClassDestructors::contains) - .collect( - Collectors.toList()); + List commonFunctions1 = allClassConstructors.stream() + .distinct() + .filter(allClassDestructors::contains) + .collect(Collectors.toList()); - List commonFunctions2 = - allClassDestructors.stream() - .distinct() - .filter(allClassConstructors::contains) - .collect( - Collectors.toList()); + List commonFunctions2 = allClassDestructors.stream() + .distinct() + .filter(allClassConstructors::contains) + .collect(Collectors.toList()); if (commonFunctions1.isEmpty() && commonFunctions2.isEmpty()) { return false; @@ -638,6 +662,31 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { analyzer.added(currentProgram, set, monitor, new MessageLog()); } + /** + * If program has the "RTTI Found" option at all it means RTTI analyzer has been run and + * does not need to be run again. If program does not have the option it means either analyzer + * has not been run or it has been run by an older version (<10.3) so we don't know and should + * rerun to make sure. + * @return true if RTTI analyzer has definitely been run, false otherwise + */ + private boolean isRttiAnalyzed() { + Options programOptions = currentProgram.getOptions(Program.PROGRAM_INFO); + Boolean rttiAnalyzed = (Boolean) programOptions.getObject(RTTI_FOUND_OPTION, null); + if (rttiAnalyzed == null) { + return false; + } + return true; + } + + /** + * Method to check to see if current program has RTTI based on option setting + * @return true if program contains RTTI and false if not + */ + private boolean hasRtti() { + Options programOptions = currentProgram.getOptions(Program.PROGRAM_INFO); + return programOptions.getBoolean(RTTI_FOUND_OPTION, false); + } + /** * Get the version of Ghidra that was used to analyze this program * @return a string containing the version number of Ghidra used to analyze the current program @@ -903,12 +952,13 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { } /** - * Method to print class hierarchies for the given list of classes starting with the lowest child classes in each family of classes + * Method to print class hierarchies for the given list of classes starting with the lowest + * child classes in each family of classes * @param recoveredClasses the list of classes * @throws CancelledException if cancelled */ - private void printClassHierarchiesFromLowestChildren( - List recoveredClasses) throws CancelledException { + private void printClassHierarchiesFromLowestChildren(List recoveredClasses) + throws CancelledException { StringBuffer wholeBuffer = new StringBuffer(); wholeBuffer.append("\r\n"); @@ -969,7 +1019,8 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { } /** - * Method to print counts of various class items for the given classes, such as number of constructors, destructors, etc... + * Method to print counts of various class items for the given classes, such as number of + * constructors, destructors, etc... * @param recoveredClasses list of classes * @throws CancelledException if cancelled */ @@ -979,14 +1030,12 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { recoverClassesFromRTTI.getNumberOfConstructors(recoveredClasses)); println("Total number of inlined constructors: " + getNumberOfInlinedConstructors(recoveredClasses)); - println( - "Total number of destructors: " + - recoverClassesFromRTTI.getNumberOfDestructors(recoveredClasses)); + println("Total number of destructors: " + + recoverClassesFromRTTI.getNumberOfDestructors(recoveredClasses)); println("Total number of inlined destructors: " + recoverClassesFromRTTI.getNumberOfInlineDestructors(recoveredClasses)); - println( - "Total number of virtual functions: " + - recoverClassesFromRTTI.getNumberOfVirtualFunctions(recoveredClasses)); + println("Total number of virtual functions: " + + recoverClassesFromRTTI.getNumberOfVirtualFunctions(recoveredClasses)); println("Total number of virtual functions that are deleting destructors: " + recoverClassesFromRTTI.getNumberOfDeletingDestructors(recoveredClasses)); @@ -1090,7 +1139,8 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { /** * Method to get formatted string containing the given class, it's parents and it's children * @param recoveredClass the given classes - * @return StringBuffer containing the formatted string containing the given class, it's parents and it's children + * @return StringBuffer containing the formatted string containing the given class, it's parents + * and it's children * @throws CancelledException if cancelled */ private StringBuffer printClassParentsandChildren(RecoveredClass recoveredClass) @@ -1128,8 +1178,9 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { } /** - * Method to create a string containing class info for the given class including parents, children, constructors, destructors - * inlined constructors, inlined destructors, member functions, member data and the same info for each child class + * Method to create a string containing class info for the given class including parents, + * children, constructors, destructors inlined constructors, inlined destructors, member + * functions, member data and the same info for each child class * @param recoveredClass the given class * @return string buffer containing class info for the given class * @throws CancelledException if cancelled @@ -1163,12 +1214,10 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { Boolean isVirtualParent = parentToBaseTypeMap.get(ancestor); if (isVirtualParent != null && isVirtualParent) { - stringBuffer.append( - "\t virtual " + ancestor.getName() + "\r\n"); + stringBuffer.append("\t virtual " + ancestor.getName() + "\r\n"); } else { - stringBuffer.append( - "\t" + ancestor.getName() + "\r\n"); + stringBuffer.append("\t" + ancestor.getName() + "\r\n"); } } } @@ -1251,8 +1300,8 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { List virtualFunctions = recoveredClass.getAllVirtualFunctions(); for (Function vfunction : virtualFunctions) { monitor.checkCanceled(); - stringBuffer.append("\t" + vfunction.getName() + " " + - vfunction.getEntryPoint().toString() + "\r\n"); + stringBuffer.append( + "\t" + vfunction.getName() + " " + vfunction.getEntryPoint().toString() + "\r\n"); } stringBuffer.append("\r\n"); @@ -1364,8 +1413,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { List constructorList = recoveredClass.getConstructorList(); for (Function constructorFunction : constructorList) { monitor.checkCanceled(); - String functionSignatureString = - getFunctionSignatureString(constructorFunction, true); + String functionSignatureString = getFunctionSignatureString(constructorFunction, true); stringBuffer.append(functionSignatureString); stringBuffer.append("\r\n"); @@ -1376,8 +1424,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { List destructorList = recoveredClass.getDestructorList(); for (Function destructorFunction : destructorList) { monitor.checkCanceled(); - String functionSignatureString = - getFunctionSignatureString(destructorFunction, true); + String functionSignatureString = getFunctionSignatureString(destructorFunction, true); stringBuffer.append(functionSignatureString); stringBuffer.append("\r\n"); } @@ -1400,8 +1447,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { List virtualFunctions = recoveredClass.getAllVirtualFunctions(); for (Function vfunction : virtualFunctions) { monitor.checkCanceled(); - String functionSignatureString = - getFunctionSignatureString(vfunction, true); + String functionSignatureString = getFunctionSignatureString(vfunction, true); stringBuffer.append(functionSignatureString); stringBuffer.append("\r\n"); } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java index 4549d939ed..f63ce5876f 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java @@ -287,7 +287,6 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { List vftableSymbols = createMissingVftableSymbols(completeObjectLocatorSymbols); return vftableSymbols; - } /** @@ -447,8 +446,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { Data baseClassDescriptor = extendedFlatAPI.getDataAt(baseClassDescriptorAddress); if (baseClassDescriptor == null || !baseClassDescriptor.getDataType() .getName() - .equals( - RTTI_BASE_CLASS_DESCRIPTOR_DATA_NAME)) { + .equals(RTTI_BASE_CLASS_DESCRIPTOR_DATA_NAME)) { int num1 = extendedFlatAPI.getInt(baseClassDescriptorAddress.add(8)); int num2 = extendedFlatAPI.getInt(baseClassDescriptorAddress.add(12)); @@ -531,11 +529,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { Data classHierarchyStructure = extendedFlatAPI.getDataAt(classHierarchyDescriptorAddress); - if (classHierarchyStructure != null && - classHierarchyStructure.getDataType() - .getName() - .equals( - RTTI_CLASS_HIERARCHY_DESCRIPTOR_DATA_NAME)) { + if (classHierarchyStructure != null && classHierarchyStructure.getDataType() + .getName() + .equals(RTTI_CLASS_HIERARCHY_DESCRIPTOR_DATA_NAME)) { return classHierarchyDescriptorAddress; } @@ -842,8 +838,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { private void createMissingFunctions(List vftableSymbols) throws CancelledException, Exception { - List
unusedVftableReferences = - findVftableReferencesNotInFunction(vftableSymbols); + List
unusedVftableReferences = findVftableReferencesNotInFunction(vftableSymbols); if (unusedVftableReferences.size() > 0) { extendedFlatAPI.createUndefinedFunctions(unusedVftableReferences); @@ -1146,8 +1141,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { List classHierarchy = new ArrayList(); List symbols = extendedFlatAPI.getListOfSymbolsByNameInNamespace( - RTTI_BASE_CLASS_ARRAY_LABEL, - recoveredClass.getClassNamespace(), false); + RTTI_BASE_CLASS_ARRAY_LABEL, recoveredClass.getClassNamespace(), false); if (symbols.size() == 1) { Symbol rttiBaseClassSymbol = symbols.get(0); @@ -1269,7 +1263,6 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { Msg.debug(this, recoveredClass.getName() + " has ambiguous inh type"); } - } /** @@ -1337,8 +1330,6 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { } - - /** * Method to recover parent information, including class offsets, vbase structure and its offset and address if applicable, and whether * the parent is regularly or virtually inherited @@ -1495,8 +1486,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { continue; } - FillOutStructureCmd fillCmd = - new FillOutStructureCmd(program, location, tool); + FillOutStructureCmd fillCmd = new FillOutStructureCmd(program, location, tool); Address vbtableAddress = getVbtableAddressFromDecompiledFunction(fillCmd, highFunction, recoveredClass, constructor, vbtableOffset); @@ -1526,8 +1516,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { continue; } - FillOutStructureCmd fillCmd = - new FillOutStructureCmd(program, location, tool); + FillOutStructureCmd fillCmd = new FillOutStructureCmd(program, location, tool); Address vbtableAddress = getVbtableAddressFromDecompiledFunction(fillCmd, highFunction, recoveredClass, constructor, vbtableOffset); @@ -1665,8 +1654,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { List parents = new ArrayList(recoveredClass.getClassHierarchyMap().keySet()); RecoveredClass singleParent = parents.get(0); - List grandParents = - getParentsWithVirtualFunctions(singleParent); + List grandParents = getParentsWithVirtualFunctions(singleParent); // check that they both have vftables // get their order from the class hierarchy list // first see if it has a parent order map and just make it the same one @@ -2200,18 +2188,15 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { // create pointers to empty vftable structs so they can be added to the class data type // then filled in later - Map vfPointerDataTypes = - createEmptyVfTableStructs(recoveredClass); + Map vfPointerDataTypes = createEmptyVfTableStructs(recoveredClass); // create current class structure and add pointer to vftable, all parent member data strutures, and class member data structure Structure classStruct = null; - classStruct = createClassStructureUsingRTTI(recoveredClass, - vfPointerDataTypes); + classStruct = createClassStructureUsingRTTI(recoveredClass, vfPointerDataTypes); applyVbtableStructure(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 @@ -2392,8 +2377,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { // if it fits at offset or is at the end and class structure can be grown, // copy the whole baseClass structure to the class Structure at the given offset - EditStructureUtils.addDataTypeToStructure(classStructureDataType, - baseClassOffset, baseClassStructure, baseClassStructure.getName(), monitor); + EditStructureUtils.addDataTypeToStructure(classStructureDataType, baseClassOffset, + baseClassStructure, baseClassStructure.getName(), monitor); } @@ -2421,8 +2406,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { // if it fits at offset or is at the end and class structure can be grown, // copy the whole baseClass structure to the class Structure at the given offset - EditStructureUtils.addDataTypeToStructure(classStructureDataType, - offset.intValue(), classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor); + EditStructureUtils.addDataTypeToStructure(classStructureDataType, offset.intValue(), + classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor); } // add the vbtable structure for single inheritance/virt parent case @@ -2769,25 +2754,23 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { * @return the newly created jumped to function or null if it cannot be created */ private Function createSplitDeletingDestructorFunction(AddressSetView body) { - + if (body.getNumAddressRanges() != 2) { return null; } AddressRange firstRange = body.getFirstRange(); Address maxAddressofFirstRange = firstRange.getMaxAddress(); - Instruction instructionContaining = - api.getInstructionContaining(maxAddressofFirstRange); + Instruction instructionContaining = api.getInstructionContaining(maxAddressofFirstRange); if (!instructionContaining.getFlowType().isJump()) { return null; } AddressRange lastRange = body.getLastRange(); Address minAddressOfLastRange = lastRange.getMinAddress(); - Reference reference = - api.getReference(instructionContaining, minAddressOfLastRange); + Reference reference = api.getReference(instructionContaining, minAddressOfLastRange); if (reference == null) { return null; } - instructionContaining.setFlowOverride(FlowOverride.CALL_RETURN); + instructionContaining.setFlowOverride(FlowOverride.CALL_RETURN); Function newFunction = api.createFunction(minAddressOfLastRange, null); return newFunction; } @@ -2836,4 +2819,3 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { } } - diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/plugin/prototype/MicrosoftCodeAnalyzerPlugin/RttiAnalyzer.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/plugin/prototype/MicrosoftCodeAnalyzerPlugin/RttiAnalyzer.java index e45a41d74d..038de3f0bb 100644 --- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/plugin/prototype/MicrosoftCodeAnalyzerPlugin/RttiAnalyzer.java +++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/plugin/prototype/MicrosoftCodeAnalyzerPlugin/RttiAnalyzer.java @@ -23,6 +23,7 @@ import ghidra.app.cmd.data.rtti.*; import ghidra.app.services.*; import ghidra.app.util.datatype.microsoft.*; import ghidra.app.util.importer.MessageLog; +import ghidra.framework.options.Options; import ghidra.program.model.address.*; import ghidra.program.model.data.InvalidDataTypeException; import ghidra.program.model.listing.Program; @@ -41,6 +42,7 @@ public class RttiAnalyzer extends AbstractAnalyzer { private static final String NAME = "Windows x86 PE RTTI Analyzer"; private static final String DESCRIPTION = "Finds and creates RTTI metadata structures and associated vf tables."; + public static final String RTTI_FOUND_OPTION = "RTTI Found"; // TODO If we want the RTTI analyzer to find all type descriptors regardless of whether // they are used for RTTI, then change the CLASS_PREFIX_CHARS to ".". Need to be @@ -61,7 +63,7 @@ public class RttiAnalyzer extends AbstractAnalyzer { setPriority(AnalysisPriority.REFERENCE_ANALYSIS.before()); setDefaultEnablement(true); validationOptions = new DataValidationOptions(); - applyOptions = new DataApplyOptions(); + applyOptions = new DataApplyOptions(); } @Override @@ -72,10 +74,16 @@ public class RttiAnalyzer extends AbstractAnalyzer { @Override public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) throws CancelledException { - + + // "rttiFound" option added in 10.3 so if analyzed with previous version analyzer will rerun + if(hasRun(program)) { + return true; + } + Address commonVfTableAddress = RttiUtil.findTypeInfoVftableAddress(program, monitor); - if (commonVfTableAddress == null) { + if (commonVfTableAddress == null) { + setRttiFound(program, false); return true; } @@ -83,14 +91,42 @@ public class RttiAnalyzer extends AbstractAnalyzer { Set
possibleTypeAddresses = locatePotentialRTTI0Entries(program, set, monitor); if (possibleTypeAddresses == null) { + setRttiFound(program, false); return true; } // We now have a list of potential rtti0 addresses. processRtti0(possibleTypeAddresses, program, monitor); - + setRttiFound(program, true); + return true; } + + /** + * Has this analyzer been run on the given program. NOTE: option new as of 10.3 so this will + * not be accurate for older programs. + * @param program the given program + * @return true if analyzer has run, false if not or unknown (before version 10.3) + */ + private boolean hasRun(Program program) { + Options programOptions = program.getOptions(Program.PROGRAM_INFO); + Boolean hasRun = (Boolean) programOptions.getObject(RTTI_FOUND_OPTION, null); + if(hasRun == null) { + return false; + } + return true; + + } + + /** + * Method to set the RTTI Found option for the given program + * @param program the given program + * @param rttiFound true if RTTI found and processed, false otherwise + */ + private void setRttiFound(Program program, boolean rttiFound) { + Options programOptions = program.getOptions(Program.PROGRAM_INFO); + programOptions.setBoolean(RTTI_FOUND_OPTION, rttiFound); + } /** * locate any potential RTTI0 based on pointers to the type_info vftable @@ -98,7 +134,7 @@ public class RttiAnalyzer extends AbstractAnalyzer { * @param set restricted set to locate within * @param monitor monitor for canceling * @return set of potential RTTI0 entries - * @throws CancelledException + * @throws CancelledException if cancelled */ private Set
locatePotentialRTTI0Entries(Program program, AddressSetView set, TaskMonitor monitor) throws CancelledException {