diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java b/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java index 5f91b5457a..2a5b8e24ee 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java @@ -34,7 +34,7 @@ // NOTE: As this is a prototype script, the location, names, and design of data types created by // 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 +// 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 // virtual inheritance but if the program contains DWARF, there will be some amount of data recovered // by the DWARF analyzer. @@ -54,10 +54,20 @@ import java.io.File; import java.io.PrintWriter; -import java.util.*; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; -import classrecovery.*; +import classrecovery.DecompilerScriptUtils; +import classrecovery.RTTIClassRecoverer; +import classrecovery.RTTIGccClassRecoverer; +import classrecovery.RTTIWindowsClassRecoverer; +import classrecovery.RecoveredClass; +import classrecovery.RecoveredClassHelper; import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.decompiler.DecompInterface; import ghidra.app.plugin.core.analysis.AutoAnalysisManager; @@ -71,15 +81,32 @@ import ghidra.app.util.bin.format.dwarf4.next.sectionprovider.DWARFSectionProvid 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.app.util.opinion.ElfLoader; +import ghidra.app.util.opinion.PeLoader; import ghidra.framework.options.Options; import ghidra.framework.plugintool.PluginTool; -import ghidra.program.model.address.*; -import ghidra.program.model.data.*; -import ghidra.program.model.listing.*; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressSet; +import ghidra.program.model.address.AddressSetView; +import ghidra.program.model.data.CategoryPath; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.DataTypeComponent; +import ghidra.program.model.data.DataTypeManager; +import ghidra.program.model.data.Structure; +import ghidra.program.model.listing.Function; +import ghidra.program.model.listing.Parameter; +import ghidra.program.model.listing.Program; import ghidra.program.model.mem.MemoryBlock; import ghidra.program.util.GhidraProgramUtilities; -import ghidra.service.graph.*; +import ghidra.service.graph.AttributedEdge; +import ghidra.service.graph.AttributedGraph; +import ghidra.service.graph.AttributedVertex; +import ghidra.service.graph.GraphDisplay; +import ghidra.service.graph.GraphDisplayOptions; +import ghidra.service.graph.GraphDisplayOptionsBuilder; +import ghidra.service.graph.GraphDisplayProvider; +import ghidra.service.graph.GraphType; +import ghidra.service.graph.GraphTypeBuilder; +import ghidra.service.graph.VertexShape; import ghidra.util.exception.CancelledException; import ghidra.util.exception.GraphException; import ghidra.util.task.TaskMonitor; @@ -140,10 +167,8 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { private static final String DESTRUCTOR_BOOKMARK = "DESTRUCTOR"; private static final String INDETERMINATE_BOOKMARK = "INDETERMINATE"; - - boolean hasDebugSymbols; - boolean isGcc = false; - boolean isWindows = false; + boolean programHasRTTIApplied = false; + boolean hasDebugSymbols = false; String ghidraVersion = null; DecompilerScriptUtils decompilerUtils; @@ -159,15 +184,16 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { @Override public void run() throws Exception { - + String errorMsg = validate(); + if (!errorMsg.isEmpty()) { println(errorMsg); return; } - - if (isWindows()) { - + + if (!isGcc() && isWindows()) { + if (!isRttiAnalyzed()) { println("Running the RTTIAnalyzer..."); analysisMode = AnalysisMode.ENABLED; @@ -192,11 +218,27 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { this, BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS, nameVfunctions, hasDebugSymbols, monitor); } + else if (isPE() && isGcc()){ + + println("Program is a gcc compiled PE."); + 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."); + if (!runGcc) { + return; + } + //run fixup old elf relocations script + runScript("FixElfExternalOffsetDataRelocationScript.java"); + recoverClassesFromRTTI = + new RTTIGccClassRecoverer(currentProgram, currentLocation, state.getTool(), this, + BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS, + nameVfunctions, hasDebugSymbols, monitor); + } 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."); + println("Before popping up dialog.."); + printTime(); + 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."); + if (!runGcc) { return; } @@ -376,8 +418,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { } if (!isGcc() && !isWindows()) { - return ("This script only handles Windows and gcc programs"); - + return ("This script only handles Windows PE and Gcc programs"); } defaultPointerSize = currentProgram.getDefaultPointerSize(); @@ -438,7 +479,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { AttributedGraph g = new AttributedGraph("Recovered Classes Graph", graphType); for (RecoveredClass recoveredClass : recoveredClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); AttributedVertex classVertex = g.addVertex(recoveredClass.getClassPath().getPath(), recoveredClass.getName()); @@ -470,7 +511,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { recoveredClass.getParentToBaseTypeMap(); for (RecoveredClass parent : parents) { - monitor.checkCanceled(); + monitor.checkCancelled(); AttributedVertex parentVertex = g.addVertex(parent.getClassPath().getPath(), parent.getName()); @@ -541,11 +582,11 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { throws CancelledException { for (RecoveredClass recoveredClass : recoveredClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); List classHierarchyList = recoveredClass.getClassHierarchy(); for (RecoveredClass currentClass : classHierarchyList) { - monitor.checkCanceled(); + monitor.checkCancelled(); println(currentClass.getName()); } @@ -567,15 +608,26 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { } return false; } + + + /** + * Method to check if executable format is PE + */ + private boolean isPE() { + + if (!PeLoader.PE_NAME.equals(currentProgram.getExecutableFormat())) { + return false; + } + return true; + + } /** * Method to set the global variable isGcc */ private boolean isGcc() { - if (!ElfLoader.ELF_NAME.equals(currentProgram.getExecutableFormat())) { - return false; - } + boolean isGcc; boolean isCompilerSpecGcc = currentProgram.getCompilerSpec() .getCompilerSpecID() @@ -584,6 +636,11 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { if (isCompilerSpecGcc) { return true; } + + String compiler = currentProgram.getCompiler(); + if(compiler != null && compiler.contains("gcc")) { + return true; + } MemoryBlock commentBlock = currentProgram.getMemory().getBlock(".comment"); if (commentBlock == null) { @@ -610,6 +667,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { return isGcc; } + /** * Method to set the global variable isWindows @@ -618,7 +676,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { String compilerID = currentProgram.getCompilerSpec().getCompilerSpecID().getIdAsString().toLowerCase(); - isWindows = compilerID.contains("windows"); + boolean isWindows = compilerID.contains("windows"); return isWindows; } @@ -741,7 +799,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { stringBuffer.append(" : "); int lastColon = stringBuffer.lastIndexOf(":"); for (RecoveredClass parentClass : classHierarchyMap.keySet()) { - monitor.checkCanceled(); + monitor.checkCancelled(); if (classHierarchyMap.size() == 1) { //stringBuffer.append(" : "); getSimpleClassHierarchyString(stringBuffer, parentClass); @@ -752,7 +810,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { //int lastColon = stringBuffer.lastIndexOf(":"); for (int i = 0; i <= lastColon; i++) { - monitor.checkCanceled(); + monitor.checkCancelled(); stringBuffer.append(" "); } getSimpleClassHierarchyString(stringBuffer, parentClass); @@ -775,7 +833,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { MemoryBlock[] blocks = currentProgram.getMemory().getBlocks(); for (MemoryBlock block : blocks) { - monitor.checkCanceled(); + monitor.checkCancelled(); if (block.isInitialized()) { dataAddresses.add(block.getStart(), block.getEnd()); @@ -793,7 +851,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { throws CancelledException { for (RecoveredClass recoveredClass : recoveredClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); bookmarkFunctionsOnList(recoveredClass.getConstructorList(), CONSTRUCTOR_BOOKMARK); } } @@ -807,7 +865,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { throws CancelledException { for (RecoveredClass recoveredClass : recoveredClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); bookmarkFunctionsOnList(recoveredClass.getDestructorList(), DESTRUCTOR_BOOKMARK); bookmarkFunctionsOnList(recoveredClass.getNonThisDestructors(), DESTRUCTOR_BOOKMARK); } @@ -822,7 +880,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { List recoveredClasses) throws CancelledException { for (RecoveredClass recoveredClass : recoveredClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); bookmarkFunctionsOnList(recoveredClass.getIndeterminateList(), INDETERMINATE_BOOKMARK); } } @@ -841,7 +899,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { } for (Function function : functions) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address address = function.getEntryPoint(); recoverClassesFromRTTI.bookmarkAddress(address, comment); } @@ -902,7 +960,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { private void printClassDefinitions(List recoveredClasses) throws CancelledException { for (RecoveredClass recoveredClass : recoveredClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); if (!recoveredClass.hasParentClass()) { println(createClassDefinitionString(recoveredClass).toString()); } @@ -912,7 +970,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { private void outputClassDefinitions(List recoveredClasses, PrintWriter out) throws CancelledException { for (RecoveredClass recoveredClass : recoveredClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); if (!recoveredClass.hasParentClass()) { out.append(createClassDefinitionString(recoveredClass)); } @@ -928,7 +986,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { */ private void printClassInfo(List recoveredClasses) throws CancelledException { for (RecoveredClass recoveredClass : recoveredClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); if (!recoveredClass.hasParentClass()) { println(createClassInfoString(recoveredClass).toString()); } @@ -938,12 +996,12 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { private void printClassParents(List recoveredClasses) throws CancelledException { for (RecoveredClass recoveredClass : recoveredClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); String printString = new String("\n" + recoveredClass.getName() + "\n"); if (recoveredClass.hasParentClass()) { List parentList = recoveredClass.getParentList(); for (RecoveredClass parent : parentList) { - monitor.checkCanceled(); + monitor.checkCancelled(); printString = printString.concat("\t" + parent.getName() + "\n"); } } @@ -963,7 +1021,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { StringBuffer wholeBuffer = new StringBuffer(); wholeBuffer.append("\r\n"); for (RecoveredClass recoveredClass : recoveredClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); if (!recoveredClass.hasChildClass()) { StringBuffer stringBuffer = new StringBuffer(); @@ -990,7 +1048,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { wholeBuffer.append("\r\n"); for (RecoveredClass recoveredClass : recoveredClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); if (!recoveredClass.hasChildClass()) { StringBuffer stringBuffer = new StringBuffer(); wholeBuffer.append( @@ -1011,7 +1069,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { throws CancelledException { for (RecoveredClass recoveredClass : recoveredClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); if (!recoveredClass.hasParentClass()) { out.append(createClassInfoString(recoveredClass).toString()); } @@ -1070,7 +1128,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { int total = 0; for (RecoveredClass recoveredClass : recoveredClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); List constructorList = recoveredClass.getConstructorOrDestructorFunctions(); total += constructorList.size(); } @@ -1088,7 +1146,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { int total = 0; for (RecoveredClass recoveredClass : recoveredClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); List inlineList = recoveredClass.getInlinedConstructorList(); total += inlineList.size(); } @@ -1102,7 +1160,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { */ private void printAddresses(List
addresses) throws CancelledException { for (Address element : addresses) { - monitor.checkCanceled(); + monitor.checkCancelled(); println(element.toString()); } } @@ -1117,7 +1175,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { PrintWriter out) throws CancelledException { for (RecoveredClass recoveredClass : recoveredClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); out.append(printClassParentsandChildren(recoveredClass)); } } @@ -1131,7 +1189,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { throws CancelledException { for (RecoveredClass recoveredClass : recoveredClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); println(printClassParentsandChildren(recoveredClass).toString()); } } @@ -1157,7 +1215,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { if (recoveredClass.hasParentClass()) { Set keySet = recoveredClass.getClassHierarchyMap().keySet(); for (RecoveredClass parent : keySet) { - monitor.checkCanceled(); + monitor.checkCancelled(); stringBuffer.append("\t" + parent.getName() + "\r\n"); } } @@ -1168,7 +1226,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { if (recoveredClass.hasChildClass()) { List childClasses = recoveredClass.getChildClasses(); for (RecoveredClass element : childClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); stringBuffer.append("\t" + element.getName() + "\r\n"); } @@ -1209,7 +1267,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { recoveredClass.getParentToBaseTypeMap(); Set ancestors = parentToBaseTypeMap.keySet(); for (RecoveredClass ancestor : ancestors) { - monitor.checkCanceled(); + monitor.checkCancelled(); if (directParents.contains(ancestor)) { Boolean isVirtualParent = parentToBaseTypeMap.get(ancestor); @@ -1232,7 +1290,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { if (recoveredClass.hasChildClass()) { List childClasses = recoveredClass.getChildClasses(); for (RecoveredClass element : childClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); stringBuffer.append("\t" + element.getName() + "\r\n"); } @@ -1243,7 +1301,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { stringBuffer.append("constructor(s):\r\n"); List constructorList = recoveredClass.getConstructorList(); for (Function constructorFunction : constructorList) { - monitor.checkCanceled(); + monitor.checkCancelled(); stringBuffer.append("\t" + constructorFunction.getName() + " " + constructorFunction.getEntryPoint().toString() + "\r\n"); } @@ -1254,7 +1312,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { if (inlinedConstructorList.size() > 0) { stringBuffer.append("inlined constructor(s):\r\n"); for (Function inlinedConstructorFunction : inlinedConstructorList) { - monitor.checkCanceled(); + monitor.checkCancelled(); stringBuffer.append("\t" + inlinedConstructorFunction.getName() + " " + inlinedConstructorFunction.getEntryPoint().toString() + "\r\n"); } @@ -1265,7 +1323,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { stringBuffer.append("destructor(s):\r\n"); List destructorList = recoveredClass.getDestructorList(); for (Function destructorFunction : destructorList) { - monitor.checkCanceled(); + monitor.checkCancelled(); stringBuffer.append("\t" + destructorFunction.getName() + " " + destructorFunction.getEntryPoint().toString() + "\r\n"); } @@ -1276,7 +1334,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { if (inlinedDestructorList.size() > 0) { stringBuffer.append("inlined destructor(s):\r\n"); for (Function inlinedDestructorFunction : inlinedDestructorList) { - monitor.checkCanceled(); + monitor.checkCancelled(); stringBuffer.append("\t" + inlinedDestructorFunction.getName() + " " + inlinedDestructorFunction.getEntryPoint().toString() + "\r\n"); } @@ -1287,7 +1345,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { if (indeterminateList.size() > 0) { stringBuffer.append("\r\nindeterminate constructor(s) or destructor(s):\r\n"); for (Function indeterminateFunction : indeterminateList) { - monitor.checkCanceled(); + monitor.checkCancelled(); stringBuffer.append("\t" + indeterminateFunction.getName() + " " + indeterminateFunction.getEntryPoint().toString() + "\r\n"); } @@ -1299,7 +1357,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { stringBuffer.append("member function(s):\r\n"); List virtualFunctions = recoveredClass.getAllVirtualFunctions(); for (Function vfunction : virtualFunctions) { - monitor.checkCanceled(); + monitor.checkCancelled(); stringBuffer.append( "\t" + vfunction.getName() + " " + vfunction.getEntryPoint().toString() + "\r\n"); } @@ -1318,7 +1376,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { DataTypeComponent[] definedComponents = memberDataStructure.getDefinedComponents(); for (int i = 0; i < numDefinedComponents; i++) { - monitor.checkCanceled(); + monitor.checkCancelled(); stringBuffer.append("\t" + definedComponents[i].getDataType() + " " + definedComponents[i].getFieldName() + "\r\n"); @@ -1330,7 +1388,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { if (recoveredClass.hasChildClass()) { List childClasses = recoveredClass.getChildClasses(); for (RecoveredClass element : childClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); stringBuffer.append(createClassInfoString(element)); } } @@ -1377,7 +1435,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { } else { for (int i = autoParamCount - 1; i < paramCount; i++) { - monitor.checkCanceled(); + monitor.checkCancelled(); Parameter param = function.getParameter(i); stringBuffer.append(param.getDataType().getDisplayName() + " " + param.getName()); if (i == paramCount) { @@ -1412,7 +1470,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { stringBuffer.append("constructor(s):\r\n"); List constructorList = recoveredClass.getConstructorList(); for (Function constructorFunction : constructorList) { - monitor.checkCanceled(); + monitor.checkCancelled(); String functionSignatureString = getFunctionSignatureString(constructorFunction, true); stringBuffer.append(functionSignatureString); @@ -1423,7 +1481,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { stringBuffer.append("\r\ndestructor(s):\r\n"); List destructorList = recoveredClass.getDestructorList(); for (Function destructorFunction : destructorList) { - monitor.checkCanceled(); + monitor.checkCancelled(); String functionSignatureString = getFunctionSignatureString(destructorFunction, true); stringBuffer.append(functionSignatureString); stringBuffer.append("\r\n"); @@ -1434,7 +1492,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { if (indeterminateList.size() > 0) { stringBuffer.append("\r\nindeterminate constructor or destructor function(s):\r\n"); for (Function indeterminateFunction : indeterminateList) { - monitor.checkCanceled(); + monitor.checkCancelled(); String functionSignatureString = getFunctionSignatureString(indeterminateFunction, true); stringBuffer.append(functionSignatureString); @@ -1446,7 +1504,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { stringBuffer.append("\r\nmember function(s):\r\n"); List virtualFunctions = recoveredClass.getAllVirtualFunctions(); for (Function vfunction : virtualFunctions) { - monitor.checkCanceled(); + monitor.checkCancelled(); String functionSignatureString = getFunctionSignatureString(vfunction, true); stringBuffer.append(functionSignatureString); stringBuffer.append("\r\n"); @@ -1466,7 +1524,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { DataTypeComponent[] definedComponents = memberDataStructure.getDefinedComponents(); for (int i = 0; i < numDefinedComponents; i++) { - monitor.checkCanceled(); + monitor.checkCancelled(); stringBuffer.append("\t" + definedComponents[i].getDataType() + " " + definedComponents[i].getFieldName() + "\r\n"); } @@ -1477,7 +1535,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { if (recoveredClass.hasChildClass()) { List childClasses = recoveredClass.getChildClasses(); for (RecoveredClass element : childClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); stringBuffer.append(createClassDefinitionString(element)); } } @@ -1485,4 +1543,12 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { return stringBuffer; } + + private void printTime() { + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"); + LocalDateTime now = LocalDateTime.now(); + println(dtf.format(now)); + } + + } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/BaseTypeinfo.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/BaseTypeinfo.java new file mode 100644 index 0000000000..8142039e36 --- /dev/null +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/BaseTypeinfo.java @@ -0,0 +1,64 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package classrecovery; + +public class BaseTypeinfo { + + GccTypeinfo baseTypeinfo; + int baseOrder; + boolean isPublic; + boolean isVirtual; + long offset; + + public BaseTypeinfo(GccTypeinfo baseTypeinfo, int baseOrder, boolean isPublic, boolean isVirtual, long offset){ + this.baseTypeinfo = baseTypeinfo; + this.baseOrder = baseOrder; + this.isPublic = isPublic; + this.isVirtual = isVirtual; + this.offset = offset; + } + + public GccTypeinfo getBaseTypeinfo() { + return baseTypeinfo; + } + + public boolean isPublicBase() { + return isPublic; + } + + public boolean isVirtualBase() { + return isVirtual; + } + + public long getOffset() { + return offset; + } + + public boolean isClassObjectOffset() { + if(isVirtual) { + return false; + } + return true; + } + + public boolean isVbaseOffset() { + if(isVirtual) { + return true; + } + return false; + } + +} diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/EditStructureUtils.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/EditStructureUtils.java index 45e1936775..4b57419c3c 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/EditStructureUtils.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/EditStructureUtils.java @@ -49,12 +49,16 @@ class EditStructureUtils { for (DataTypeComponent newStructComponent : newStructComponents) { - monitor.checkCanceled(); + monitor.checkCancelled(); int structOffset = newStructComponent.getOffset(); DataTypeComponent currentComponentAtOffset = containingStruct.getComponentAt(offset + structOffset); + + if(currentComponentAtOffset == null) { + continue; + } DataType newStructCompDt = newStructComponent.getDataType(); DataType containingComDt = currentComponentAtOffset.getDataType(); @@ -104,7 +108,7 @@ class EditStructureUtils { } for (int i = offset; i < offset + length; i++) { - monitor.checkCanceled(); + monitor.checkCancelled(); DataTypeComponent component = structure.getComponentAt(i); if (component == null) { return false; @@ -142,7 +146,7 @@ class EditStructureUtils { while (offset < endOfClear) { - monitor.checkCanceled(); + monitor.checkCancelled(); DataTypeComponent component = structure.getComponentContaining(offset); @@ -209,7 +213,7 @@ class EditStructureUtils { while (offset < endOfRange) { - monitor.checkCanceled(); + monitor.checkCancelled(); DataTypeComponent component = structure.getComponentContaining(offset); @@ -357,7 +361,7 @@ class EditStructureUtils { int index = offset - 1; while (index >= 0) { - monitor.checkCanceled(); + monitor.checkCancelled(); DataTypeComponent component = structure.getComponentAt(index); if (component != null && component.getDataType() == DataType.DEFAULT) { index--; @@ -385,7 +389,7 @@ class EditStructureUtils { int index = offset; while (index < structure.getLength()) { - monitor.checkCanceled(); + monitor.checkCancelled(); DataTypeComponent component = structure.getComponentAt(index); if (component.getDataType() == DataType.DEFAULT) { index++; diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/ExtendedFlatProgramAPI.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/ExtendedFlatProgramAPI.java index 8b6ac0ced8..ea4462b5d3 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/ExtendedFlatProgramAPI.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/ExtendedFlatProgramAPI.java @@ -16,19 +16,52 @@ //DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS. package classrecovery; -import java.util.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; import ghidra.app.cmd.function.CreateFunctionCmd; import ghidra.app.plugin.core.analysis.ReferenceAddressPair; import ghidra.app.util.PseudoDisassembler; import ghidra.program.flatapi.FlatProgramAPI; -import ghidra.program.model.address.*; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressOutOfBoundsException; +import ghidra.program.model.address.AddressSet; +import ghidra.program.model.address.AddressSetView; import ghidra.program.model.block.CodeBlock; import ghidra.program.model.block.IsolatedEntrySubModel; -import ghidra.program.model.data.*; -import ghidra.program.model.listing.*; -import ghidra.program.model.mem.*; -import ghidra.program.model.symbol.*; +import ghidra.program.model.data.CategoryPath; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.IBO32DataType; +import ghidra.program.model.data.LongDataType; +import ghidra.program.model.data.Pointer; +import ghidra.program.model.data.PointerDataType; +import ghidra.program.model.data.Structure; +import ghidra.program.model.data.Undefined4DataType; +import ghidra.program.model.data.Undefined8DataType; +import ghidra.program.model.lang.Register; +import ghidra.program.model.listing.Data; +import ghidra.program.model.listing.Function; +import ghidra.program.model.listing.Instruction; +import ghidra.program.model.listing.InstructionIterator; +import ghidra.program.model.listing.Listing; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.DumbMemBufferImpl; +import ghidra.program.model.mem.MemBuffer; +import ghidra.program.model.mem.Memory; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.scalar.Scalar; +import ghidra.program.model.symbol.FlowType; +import ghidra.program.model.symbol.Namespace; +import ghidra.program.model.symbol.Reference; +import ghidra.program.model.symbol.ReferenceIterator; +import ghidra.program.model.symbol.SourceType; +import ghidra.program.model.symbol.Symbol; +import ghidra.program.model.symbol.SymbolIterator; +import ghidra.program.model.symbol.SymbolTable; +import ghidra.program.model.symbol.SymbolType; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; @@ -221,8 +254,18 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI { if (referencesFrom.size() != 1) { return null; } + + Address functionAddress = referencesFrom.get(0); + + Register lowBitCodeMode = currentProgram.getRegister("LowBitCodeMode"); + if(lowBitCodeMode != null) { + long longValue = functionAddress.getOffset(); + longValue = longValue & ~0x1; + functionAddress = functionAddress.getNewAddress(longValue); + } + Function function = getFunctionAt(functionAddress); if (function == null) { // try to create function @@ -597,13 +640,21 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI { try { if (addressSize == 32) { long offset32 = getInt(address); - return address.getNewAddress(offset32); + Address newAddr = address.getNewAddress(offset32); + if(currentProgram.getMemory().contains(newAddr)) { + return newAddr; + } + return null; } else if (addressSize == 64) { long offset64 = getLong(address); - return address.getNewAddress(offset64); + Address newAddr = address.getNewAddress(offset64); + if(currentProgram.getMemory().contains(newAddr)) { + return newAddr; + } + return null; } else { @@ -615,6 +666,18 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI { } } + + public long getLongValueAt(Address address) { + + MemBuffer buf = new DumbMemBufferImpl(currentProgram.getMemory(), address); + + LongDataType longDT = new LongDataType(); + + Scalar value = + (Scalar) longDT.getValue(buf, longDT.getDefaultSettings(), defaultPointerSize); + + return value.getSignedValue(); + } /** * Method to return a list of symbols with the given name and namespace. diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/GccTypeinfo.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/GccTypeinfo.java new file mode 100644 index 0000000000..9ea1557242 --- /dev/null +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/GccTypeinfo.java @@ -0,0 +1,179 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package classrecovery; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import ghidra.program.model.address.Address; +import ghidra.program.model.symbol.Namespace; + +public class GccTypeinfo extends Typeinfo { + + private static final String CLASS_TYPEINFO_NAMESPACE = "__class_type_info"; + private static final String SI_CLASS_TYPEINFO_NAMESPACE = "__si_class_type_info"; + private static final String VMI_CLASS_TYPEINFO_NAMESPACE = "__vmi_class_type_info"; + + boolean isSpecialTypeinfo; + GccTypeinfo inheritedSpecialTypeinfo = null; + Address vtableAddress; + boolean inProgramMemory; + String mangledNamespaceString = null; + long inheritanceFlagValue; + + List baseTypeinfos = new ArrayList(); + + public GccTypeinfo(Address address, Namespace classNamespace, boolean isSpecialTypeinfo, boolean inProgramMemory){ + + super(address, classNamespace); + this.isSpecialTypeinfo = isSpecialTypeinfo; + this.inProgramMemory = inProgramMemory; + } + + public boolean isSpecialTypeinfo() { + return isSpecialTypeinfo; + } + + public boolean isInProgramMemory() { + return inProgramMemory; + } + + public void setInheritedSpecialTypeinfo(GccTypeinfo specialTypeinfo) { + inheritedSpecialTypeinfo = specialTypeinfo; + } + + + public GccTypeinfo getInheritedSpecialTypeinfo() { + return inheritedSpecialTypeinfo; + } + + + public void setVtableAddress(Address address) { + vtableAddress = address; + } + + public Address getVtableAddress() { + return vtableAddress; + } + + public void setMangledNamespaceString(String string) { + mangledNamespaceString = string; + } + + public String getMangledNamespaceString() { + return mangledNamespaceString; + } + + public void addBaseTypeinfo(GccTypeinfo baseTypeinfo, int order, boolean isPublic, boolean isVirtual, long offset) { + baseTypeinfos.add(new BaseTypeinfo(baseTypeinfo, order, isPublic, isVirtual, offset)); + } + + public List getBaseTypeinfos(){ + return baseTypeinfos; + } + + public List getAllBaseTypeinfos(){ + + Set bases = new HashSet(); + bases.addAll(getBaseTypeinfos()); + + List basesList = new ArrayList(bases); + for(BaseTypeinfo base : basesList) { + bases.addAll(base.getBaseTypeinfo().getBaseTypeinfos()); + } + + return new ArrayList(bases); + + } + + public int getNumDirectVirtualBases() { + + int numVirtualBases = 0; + for(BaseTypeinfo baseTypeinfo : baseTypeinfos) { + if(baseTypeinfo.isVirtualBase()) { + numVirtualBases++; + } + } + return numVirtualBases; + } + + public int getNumAllVirtualBases() { + int numVirtualBases = 0; + List allBaseTypeinfos = getAllBaseTypeinfos(); + for(BaseTypeinfo baseTypeinfo : allBaseTypeinfos) { + if(baseTypeinfo.isVirtualBase()) { + numVirtualBases++; + } + } + return numVirtualBases; + } + + + public List getDirectBases(){ + + List bases = new ArrayList (); + for(BaseTypeinfo baseTypeinfo : baseTypeinfos) { + bases.add(baseTypeinfo.getBaseTypeinfo()); + } + return bases; + } + + public List getAllBases(){ + + List allBaseTypeinfos = getAllBaseTypeinfos(); + Set bases = new HashSet(); + + for(BaseTypeinfo base : allBaseTypeinfos) { + bases.add(base.getBaseTypeinfo()); + } + + return new ArrayList(bases); + + } + + + public void addInheritanceFlagValue(long flagValue) { + inheritanceFlagValue = flagValue; + } + + public long getInheritanceFlagValue() { + return inheritanceFlagValue; + } + + public boolean isClassTypeinfo() { + if(inheritedSpecialTypeinfo.getNamespace().getName().equals(CLASS_TYPEINFO_NAMESPACE)) { + return true; + } + return false; + } + + public boolean isSiClassTypeinfo() { + if(inheritedSpecialTypeinfo.getNamespace().getName().equals(SI_CLASS_TYPEINFO_NAMESPACE)) { + return true; + } + return false; + } + + public boolean isVmiClassTypeinfo() { + if(inheritedSpecialTypeinfo.getNamespace().getName().equals(VMI_CLASS_TYPEINFO_NAMESPACE)) { + return true; + } + return false; + } + +} diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/GccTypeinfoRef.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/GccTypeinfoRef.java new file mode 100644 index 0000000000..0a1d8d0730 --- /dev/null +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/GccTypeinfoRef.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package classrecovery; + +import ghidra.program.model.address.Address; + +public class GccTypeinfoRef extends TypeinfoRef{ + + private Boolean inVtable = null; + + GccTypeinfoRef(Address address, Typeinfo typeinfo){ + super(address, typeinfo); + } + + GccTypeinfoRef(Address address, Typeinfo typeinfo, Boolean inVtable){ + super(address, typeinfo); + this.inVtable = inVtable; + } + + public void setIsInVtable(Boolean setting) { + inVtable = setting; + } + + public Boolean isInVtable() { + return inVtable; + } +} diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java index 9c8ce02f3f..f75fecc4ec 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java @@ -16,39 +16,107 @@ //DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS. package classrecovery; -import java.util.*; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; import ghidra.app.cmd.label.DemanglerCmd; +import ghidra.app.plugin.core.analysis.ReferenceAddressPair; import ghidra.app.util.NamespaceUtils; -import ghidra.app.util.demangler.*; -import ghidra.app.util.opinion.ElfLoader; import ghidra.framework.plugintool.PluginTool; import ghidra.program.flatapi.FlatProgramAPI; -import ghidra.program.model.address.*; -import ghidra.program.model.data.*; -import ghidra.program.model.listing.*; -import ghidra.program.model.mem.*; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressIterator; +import ghidra.program.model.address.AddressOutOfBoundsException; +import ghidra.program.model.address.AddressRange; +import ghidra.program.model.address.AddressRangeIterator; +import ghidra.program.model.address.AddressSet; +import ghidra.program.model.address.AddressSetView; +import ghidra.program.model.data.ArrayDataType; +import ghidra.program.model.data.CategoryPath; +import ghidra.program.model.data.CharDataType; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.DataTypeComponent; +import ghidra.program.model.data.DataTypeConflictHandler; +import ghidra.program.model.data.InvalidDataTypeException; +import ghidra.program.model.data.LongDataType; +import ghidra.program.model.data.LongLongDataType; +import ghidra.program.model.data.Pointer; +import ghidra.program.model.data.PointerDataType; +import ghidra.program.model.data.PointerTypedef; +import ghidra.program.model.data.StringDataType; +import ghidra.program.model.data.Structure; +import ghidra.program.model.data.StructureDataType; +import ghidra.program.model.data.UnsignedIntegerDataType; +import ghidra.program.model.lang.Register; +import ghidra.program.model.listing.Bookmark; +import ghidra.program.model.listing.BookmarkType; +import ghidra.program.model.listing.CircularDependencyException; +import ghidra.program.model.listing.Data; +import ghidra.program.model.listing.Function; +import ghidra.program.model.listing.FunctionManager; +import ghidra.program.model.listing.Instruction; +import ghidra.program.model.listing.InstructionIterator; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.DumbMemBufferImpl; +import ghidra.program.model.mem.MemBuffer; +import ghidra.program.model.mem.Memory; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.mem.MemoryBlock; import ghidra.program.model.scalar.Scalar; -import ghidra.program.model.symbol.*; +import ghidra.program.model.symbol.Namespace; +import ghidra.program.model.symbol.Reference; +import ghidra.program.model.symbol.ReferenceIterator; +import ghidra.program.model.symbol.ReferenceManager; +import ghidra.program.model.symbol.SourceType; +import ghidra.program.model.symbol.Symbol; +import ghidra.program.model.symbol.SymbolIterator; import ghidra.program.util.ProgramLocation; import ghidra.program.util.ProgramMemoryUtil; import ghidra.util.Msg; -import ghidra.util.bytesearch.*; -import ghidra.util.exception.*; +import ghidra.util.bytesearch.GenericByteSequencePattern; +import ghidra.util.bytesearch.GenericMatchAction; +import ghidra.util.bytesearch.Match; +import ghidra.util.bytesearch.MemoryBytePatternSearcher; +import ghidra.util.exception.CancelledException; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.exception.InvalidInputException; import ghidra.util.task.TaskMonitor; public class RTTIGccClassRecoverer extends RTTIClassRecoverer { + private static final String SPECIAL_CLASS_NAMESPACE = "__cxxabiv1"; + private static final String CLASS_TYPEINFO_NAMESPACE = "__class_type_info"; + private static final String SI_CLASS_TYPEINFO_NAMESPACE = "__si_class_type_info"; + private static final String VMI_CLASS_TYPEINFO_NAMESPACE = "__vmi_class_type_info"; + private static final String TYPEINFO_LABEL = "typeinfo"; + private static final String MANGLED_CLASS_TYPEINFO_NAMESPACE = "N10__cxxabiv117__class_type_infoE"; + private static final String MANGLED_SI_CLASS_TYPEINFO_NAMESPACE = "N10__cxxabiv120__si_class_type_infoE"; + private static final String MANGLED_VMI_CLASS_TYPEINFO_NAMESPACE = "N10__cxxabiv121__vmi_class_type_infoE"; + private static final String MANGLED_VTABLE_PREFIX = "_ZTV"; + private static final String MANGLED_STRING_PREFIX = "_ZTS"; + private static final String MANGLED_TYPEINFO_PREFIX = "_ZTI"; + private static final String VMI_CLASS_TYPE_INFO_STRUCTURE = "VmiClassTypeInfoStructure"; private static final String BASE_CLASS_TYPE_INFO_STRUCTURE = "BaseClassTypeInfoStructure"; private static final String SI_CLASS_TYPE_INFO_STRUCTURE = "SiClassTypeInfoStructure"; private static final String CLASS_TYPE_INFO_STRUCTURE = "ClassTypeInfoStructure"; private static final String VTABLE_LABEL = "vtable"; + private static final String CONSTRUCTION_VTABLE_LABEL = "construction-vtable"; private static final String CLASS_VTABLE_PTR_FIELD_EXT = "vftablePtr"; private static final int NONE = -1; private static final int UNKNOWN = -2; private static final boolean DEBUG = false; + Map vtableToSizeMap = new HashMap(); + Map typeinfoToVtableMap = new HashMap(); + Map typeinfoToStructuretypeMap = new HashMap(); Map classToTypeinfoMap = new HashMap(); Address class_type_info_vtable = null; Address si_class_type_info_vtable = null; @@ -59,35 +127,43 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { int componentOffset; - List nonInheritedGccClasses = new ArrayList(); - List singleInheritedGccClasses = new ArrayList(); - List multiAndOrVirtuallyInheritedGccClasses = new ArrayList(); + Map> directRefMap = new HashMap>(); + + List nonInheritedClasses = new ArrayList(); + List singleInheritedClasses = new ArrayList(); + List multiAndOrVirtuallyInheritedClasses = new ArrayList(); List recoveredClasses = new ArrayList(); - private Map> classToParentOrderMap = - new HashMap>(); + private Map> classToParentOrderMap = new HashMap>(); - private Map> classToParentOffsetMap = - new HashMap>(); + private Map> classToParentOffsetMap = new HashMap>(); boolean isDwarfLoaded; boolean replaceClassStructs; - public RTTIGccClassRecoverer(Program program, ProgramLocation location, PluginTool tool, - FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates, - boolean nameVfunctions, boolean isDwarfLoaded, + FunctionManager functionManager = null; + + public RTTIGccClassRecoverer(Program program, ProgramLocation location, PluginTool tool, FlatProgramAPI api, + boolean createBookmarks, boolean useShortTemplates, boolean nameVfunctions, boolean isDwarfLoaded, TaskMonitor monitor) throws Exception { - super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions, - isDwarfLoaded, monitor); + super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions, isDwarfLoaded, monitor); this.isDwarfLoaded = isDwarfLoaded; + + functionManager = program.getFunctionManager(); } @Override - public boolean containsRTTI() throws CancelledException, InvalidInputException { + public boolean containsRTTI() throws CancelledException { - if (!hasSpecialVtable()) { + try { + if (!hasSpecialTypeinfos()) { + return false; + } + } catch (InvalidInputException | UnsupportedEncodingException e) { + + e.printStackTrace(); return false; } @@ -96,52 +172,280 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { @Override public boolean isValidProgramType() { - if (!isGcc()) { - return false; + + if (isGcc()) { + return true; } - return true; + + return false; } @Override public List createRecoveredClasses() throws CancelledException, Exception { + AddressSetView initializedMem = program.getMemory().getAllInitializedAddressSet(); + List directReferenceList = new ArrayList(); + + ProgramMemoryUtil.loadDirectReferenceList(program, 1, initializedMem.getMinAddress(), initializedMem, + directReferenceList, monitor); + createGlobalDirectRefMap(directReferenceList); + + Msg.debug(this, "Creating Special Typeinfos"); + List specialTypeinfos = createSpecialTypeinfos(); + if (specialTypeinfos.isEmpty()) { + Msg.debug(this, "Could not create special typeinfos"); + return null; + } + + Msg.debug(this, "Creating Special Vtables"); + List specialVtables = findSpecialVtables(specialTypeinfos); + + if (specialVtables.isEmpty()) { + Msg.debug(this, "Could not create special vtables"); + return null; + } + setComponentOffset(); - processGccRTTI(); + Msg.debug(this, "Creating Typeinfo Structs"); + List typeinfos = createTypeinfoStructs(specialTypeinfos, specialVtables); + + Msg.debug(this, "Creating Vtables"); + List vtables = processVtables(typeinfos); + + Msg.debug(this, "Creating Classes from Typeinfos"); + createClassesFromTypeinfos(typeinfos); + if (recoveredClasses == null) { - Msg.debug(this, "Could not recover gcc rtti classes"); + Msg.debug(this, "Could not recover ELF rtti classes"); return null; } if (recoveredClasses.isEmpty()) { return recoveredClasses; } + + Msg.debug(this, "Updating classes with parents and flags"); + updateClassesWithParentsAndFlags(typeinfos); - createClassHierarchyListAndMapForGcc(); + Msg.debug(this, "Updating classes with vftables"); + updateClassWithVfunctions(recoveredClasses, vtables); + + Msg.debug(this, "Creating Class Hierarchy lists and maps"); + createClassHierarchyListAndMap(); if (isDwarfLoaded) { retrieveExistingClassStructures(recoveredClasses); - assignConstructorsAndDestructorsUsingExistingName(recoveredClasses); - } - else { - processConstructorAndDestructors(); } + Msg.debug(this, "Processing constructors and destructors"); + processConstructorAndDestructors(); + + Msg.debug(this, "Creating vftable order maps"); createVftableOrderMap(recoveredClasses); + Msg.debug(this, "Figuring out class data members"); figureOutClassDataMembers(recoveredClasses); + Msg.debug(this, "Creating and Applying Class structures"); createAndApplyClassStructures(); return recoveredClasses; } + private List createSpecialTypeinfos() throws CancelledException { + + List specialGccTypeinfos = new ArrayList(); + + GccTypeinfo gccTypeinfo = findSpecialTypeinfoSymbol(CLASS_TYPEINFO_NAMESPACE, MANGLED_CLASS_TYPEINFO_NAMESPACE); + + if (gccTypeinfo != null) { + gccTypeinfo.setMangledNamespaceString(MANGLED_CLASS_TYPEINFO_NAMESPACE); + class_type_info = gccTypeinfo.getAddress(); + specialGccTypeinfos.add(gccTypeinfo); + } + + gccTypeinfo = findSpecialTypeinfoSymbol(SI_CLASS_TYPEINFO_NAMESPACE, MANGLED_SI_CLASS_TYPEINFO_NAMESPACE); + + if (gccTypeinfo != null) { + gccTypeinfo.setMangledNamespaceString(MANGLED_SI_CLASS_TYPEINFO_NAMESPACE); + si_class_type_info = gccTypeinfo.getAddress(); + specialGccTypeinfos.add(gccTypeinfo); + } + + gccTypeinfo = findSpecialTypeinfoSymbol(VMI_CLASS_TYPEINFO_NAMESPACE, MANGLED_VMI_CLASS_TYPEINFO_NAMESPACE); + + if (gccTypeinfo != null) { + gccTypeinfo.setMangledNamespaceString(MANGLED_VMI_CLASS_TYPEINFO_NAMESPACE); + vmi_class_type_info = gccTypeinfo.getAddress(); + specialGccTypeinfos.add(gccTypeinfo); + } + + return specialGccTypeinfos; + + } + + private GccTypeinfo findSpecialTypeinfoSymbol(String namespaceName, String mangledNamespaceString) + throws CancelledException { + + // try finding with normal symbol name and namespace + Symbol typeinfoSymbol = getSymbolInNamespaces(SPECIAL_CLASS_NAMESPACE, namespaceName, TYPEINFO_LABEL); + if (typeinfoSymbol == null) { + // then try finding with mangled symbol + typeinfoSymbol = findAndReturnDemangledSymbol(MANGLED_TYPEINFO_PREFIX + mangledNamespaceString, + SPECIAL_CLASS_NAMESPACE, namespaceName, TYPEINFO_LABEL); + if (typeinfoSymbol == null) { + + // then try finding vtable in fake ext mem block (in this case there is no + // typeinfo symbol because it + // is in an external prog so it is assigned to the same address as the vtable + typeinfoSymbol = findTypeinfoUsingExternalVtableSymbol(namespaceName, mangledNamespaceString); + + if (typeinfoSymbol == null) { + + // then try finding with mangled namespace string in memory + typeinfoSymbol = findTypeinfoSymbolUsingMangledNamespaceString(mangledNamespaceString, + namespaceName); + } + } + } + if (typeinfoSymbol != null) { + return createGccTypeinfo(typeinfoSymbol, true); + } + return null; + } + + private Symbol findTypeinfoUsingExternalVtableSymbol(String namespaceName, String mangledNamespaceString) + throws CancelledException { + + // try finding with normal symbol name and namespace + boolean isIndirectPointerToVtable = false; + Symbol vtableSymbol = getSymbolInNamespaces(SPECIAL_CLASS_NAMESPACE, namespaceName, VTABLE_LABEL); + if (vtableSymbol == null) { + // then try finding with mangled symbol + vtableSymbol = findAndReturnDemangledSymbol(MANGLED_VTABLE_PREFIX + mangledNamespaceString, + SPECIAL_CLASS_NAMESPACE, namespaceName, VTABLE_LABEL); + if (vtableSymbol == null) { + vtableSymbol = findAndReturnDemangledSymbol( + "__imp_" + MANGLED_VTABLE_PREFIX + mangledNamespaceString, SPECIAL_CLASS_NAMESPACE, + namespaceName, VTABLE_LABEL); + if (vtableSymbol == null) { + return null; + } + isIndirectPointerToVtable = true; + + } + + } + + Address vtableAddress = vtableSymbol.getAddress(); + + // if the vtable is not in the external block and it isn't an external address + // then + // it shouldn't be the case where the typeinfo is at the same location as the + // vtable + // since it should have enough memory for whole table then + if (!inExternalBlock(vtableAddress) && !vtableAddress.isExternalAddress() && !isIndirectPointerToVtable) { + return null; + } + + if (vtableAddress.isExternalAddress()) { + vtableAddress = getSingleReferenceTo(vtableAddress); + if (vtableAddress == null) { + return null; + } + } + + Symbol typeinfoSymbol; + try { + typeinfoSymbol = symbolTable.createLabel(vtableAddress, "typeinfo", vtableSymbol.getParentNamespace(), + SourceType.ANALYSIS); + // api.setPlateComment(typeinfoAddress, "typeinfo for " + namespace); + } catch (InvalidInputException e) { + Msg.debug(this, "Could not make typeinfo symbol at " + vtableAddress); + return null; + } + + return typeinfoSymbol; + + } + + private Namespace getOrCreateNamespace(String namespaceName, Namespace parentNamespace) { + + Namespace namespace = symbolTable.getNamespace(namespaceName, parentNamespace); + if (namespace == null) { + + try { + namespace = symbolTable.createNameSpace(parentNamespace, namespaceName, SourceType.ANALYSIS); + } catch (DuplicateNameException | InvalidInputException e) { + return null; + } + } + return namespace; + } + + // TODO: this assumes only one and returns the first found - have never seen + // more than one but should probably check + private Symbol findAndReturnDemangledSymbol(String mangledSymbolName, String specialClassNamespaceName, + String classNamespaceName, String label) { + + SymbolIterator symbolIterator = symbolTable.getSymbolIterator(mangledSymbolName, true); + if (symbolIterator.hasNext()) { + + Symbol mangledSymbol = symbolIterator.next(); + Address symbolAddress = mangledSymbol.getAddress(); + Namespace specialClassNamespace = getOrCreateNamespace(specialClassNamespaceName, globalNamespace); + if (specialClassNamespace == null) { + return null; + } + Namespace classNamespace = getOrCreateNamespace(classNamespaceName, specialClassNamespace); + if (classNamespace == null) { + return null; + } + + try { + Symbol demangledSymbol = symbolTable.createLabel(symbolAddress, label, classNamespace, + SourceType.ANALYSIS); + demangledSymbol.setPrimary(); + return demangledSymbol; + } catch (InvalidInputException e) { + return null; + } + + } + return null; + } + + // TODO: can this be used for regular ones too? + private Symbol findTypeinfoSymbolUsingMangledNamespaceString(String mangledNamespace, String namespaceName) + throws CancelledException { + + Symbol specialTypeinfoSymbol = findTypeinfoUsingMangledString(mangledNamespace); + if (specialTypeinfoSymbol == null) { + Msg.debug(this, namespaceName + " typeinfo not found"); + return null; + } + + return specialTypeinfoSymbol; + + } + + private GccTypeinfo createGccTypeinfo(Symbol typeinfoSymbol, boolean isSpecial) { + + Address typeinfoAddress = typeinfoSymbol.getAddress(); + boolean isExternal = typeinfoAddress.isExternalAddress() || inExternalBlock(typeinfoAddress); + + GccTypeinfo gccTypeinfo = new GccTypeinfo(typeinfoSymbol.getAddress(), typeinfoSymbol.getParentNamespace(), + isSpecial, !isExternal); + return gccTypeinfo; + } + private void setComponentOffset() { String processor = program.getLanguage().getProcessor().toString(); - if (processor.equals("x86") || processor.equals("MIPS") || processor.equals("PowerPC") || - processor.equals("RISCV")) { + if (processor.equals("x86") || processor.equals("MIPS") || processor.equals("PowerPC") + || processor.equals("RISCV")) { if (defaultPointerSize == 4) { componentOffset = 8; @@ -163,15 +467,21 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } + /** + * Method to set the global variable isGcc + */ private boolean isGcc() { - if (!ElfLoader.ELF_NAME.equals(program.getExecutableFormat())) { - return false; + boolean isGcc; + + boolean isCompilerSpecGcc = program.getCompilerSpec().getCompilerSpecID().getIdAsString() + .equalsIgnoreCase("gcc"); + if (isCompilerSpecGcc) { + return true; } - boolean isCompilerSpecGcc = - program.getCompilerSpec().getCompilerSpecID().getIdAsString().equalsIgnoreCase("gcc"); - if (isCompilerSpecGcc) { + String compiler = program.getCompiler(); + if (compiler != null && compiler.contains("gcc")) { return true; } @@ -188,217 +498,116 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { byte[] gccBytes = { (byte) 0x47, (byte) 0x43, (byte) 0x43, (byte) 0x3a }; byte[] maskBytes = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }; - Address found = program.getMemory() - .findBytes(commentBlock.getStart(), commentBlock.getEnd(), gccBytes, maskBytes, - true, monitor); + Address found = program.getMemory().findBytes(commentBlock.getStart(), commentBlock.getEnd(), gccBytes, + maskBytes, true, monitor); if (found == null) { - return false; + isGcc = false; + } else { + isGcc = true; } - return true; + return isGcc; } /** * 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 + * @throws CancelledException if cancelled + * @throws InvalidInputException if bad characters creating labels + * @throws UnsupportedEncodingException */ - private boolean hasSpecialVtable() throws CancelledException, InvalidInputException { + private boolean hasSpecialTypeinfos() + throws CancelledException, InvalidInputException, UnsupportedEncodingException { - boolean hasSpecialVtable = createSpecialVtables(); - return hasSpecialVtable; + SymbolIterator symbolIterator = symbolTable.getSymbolIterator("*N10__cxxabiv117__class_type_infoE*", true); + if (symbolIterator.hasNext()) { + return true; + } + + if (findSingleMangledString(MANGLED_CLASS_TYPEINFO_NAMESPACE) != null) { + return true; + } + + symbolIterator = symbolTable.getSymbolIterator("*N10__cxxabiv120__si_class_type_infoE*", true); + if (symbolIterator.hasNext()) { + return true; + } + + if (findSingleMangledString("N10__cxxabiv120__si_class_type_infoE") != null) { + return true; + } + + symbolIterator = symbolTable.getSymbolIterator("*N10__cxxabiv121__vmi_class_type_infoE*", true); + if (symbolIterator.hasNext()) { + return true; + } + + if (findSingleMangledString("N10__cxxabiv121__vmi_class_type_infoE") != null) { + return true; + } + + return false; } - private Address findSpecialVtable(String namespace, String name) throws CancelledException { - Address vtableAddress = null; + List getSpecialTypeinfoSymbols() { - Symbol symbolInNamespaces = getSymbolInNamespaces(namespace, name, VTABLE_LABEL); + List symbols = new ArrayList(); - if (symbolInNamespaces != null) { - if (!symbolInNamespaces.isPrimary()) { - symbolInNamespaces.setPrimary(); + if (class_type_info != null) { + Symbol symbol = symbolTable.getPrimarySymbol(class_type_info); + if (symbol != null && symbol.getName().equals("typeinfo")) { + symbols.add(symbol); } - vtableAddress = symbolInNamespaces.getAddress(); - - return vtableAddress; } - - // if there is just one address that has symbols containing both strings then it suggests - // mangled symbol since the above didn't find it - Address addressContainingBothStrings = - getSingleAddressOfSymbolContainingBothStrings(namespace, name); - if (addressContainingBothStrings == null) { - return null; - } - - // try demangling all the symbols at this address - Symbol[] vtableSymbols = symbolTable.getSymbols(addressContainingBothStrings); - for (Symbol vtableSymbol : vtableSymbols) { - DemanglerCmd cmd = - new DemanglerCmd(addressContainingBothStrings, vtableSymbol.getName()); - cmd.applyTo(program, monitor); - - } - - // now check again to see if we can find the namespace/name - symbolInNamespaces = getSymbolInNamespaces(namespace, name, VTABLE_LABEL); - - if (symbolInNamespaces != null) { - if (!symbolInNamespaces.isPrimary()) { - symbolInNamespaces.setPrimary(); + if (si_class_type_info != null) { + Symbol symbol = symbolTable.getPrimarySymbol(si_class_type_info); + if (symbol != null && symbol.getName().equals("typeinfo")) { + symbols.add(symbol); + } + } + if (vmi_class_type_info != null) { + Symbol symbol = symbolTable.getPrimarySymbol(vmi_class_type_info); + if (symbol != null && symbol.getName().equals("typeinfo")) { + symbols.add(symbol); } - vtableAddress = symbolInNamespaces.getAddress(); - - return vtableAddress; } - return null; - + return symbols; } - private void processGccRTTI() throws CancelledException, Exception { + //TODO: split out methods + private void updateClassesWithParentsAndFlags(List typeinfos) throws CancelledException { - // create the appropriate type of type info struct at the various typeinfo symbol locations - List
typeinfoAddresses = createTypeinfoStructs(); + // add properties and parents to each class + for(GccTypeinfo typeinfo : typeinfos) { - if (typeinfoAddresses.isEmpty()) { - return; - } + monitor.checkCancelled(); + Address typeinfoAddress = typeinfo.getAddress(); - processVtables(); - - // process vtables and create classes for the vtables that have no typeinfo - List vftableSymbols = findVftablesFromVtables(); - - recoveredClasses = recoverClassesFromVftables(vftableSymbols, true, true); - - // find all valid typeinfo symbols and get their class namespace and create RecoveredClass - // object - AddressSet nonExecutableAddressSet = program.getAddressFactory() - .getAddressSet() - .subtract(program.getMemory().getExecuteSet()); - - List typeinfoSymbols = - extendedFlatAPI.getListOfSymbolsInAddressSet(nonExecutableAddressSet, "typeinfo", true); - - // create class objects for each typeinfo struct and make class to typeinfo mapping for each - createClassesFromTypeinfoSymbols(typeinfoSymbols); - - updateClassesWithParentsAndFlags(typeinfoSymbols); - - // update the vftable offset map - Iterator recoveredClassIterator = recoveredClasses.iterator(); - while (recoveredClassIterator.hasNext()) { - - monitor.checkCanceled(); - - RecoveredClass recoveredClass = recoveredClassIterator.next(); - - List
vftableAddresses = recoveredClass.getVftableAddresses(); - - Iterator
vftableAddressIterator = vftableAddresses.iterator(); - while (vftableAddressIterator.hasNext()) { - monitor.checkCanceled(); - Address vftableAddress = vftableAddressIterator.next(); - - Address offsetAddress = vftableAddress.subtract(2 * defaultPointerSize); - int offsetValue = (int) api.getLong(offsetAddress); - - recoveredClass.addClassOffsetToVftableMapping(offsetValue, vftableAddress); - } - - } - return; - - } - - private void updateClassesWithParentsAndFlags(List typeinfoSymbols) throws Exception { - - // add properties and parents to each class - Iterator typeinfoIterator = typeinfoSymbols.iterator(); - while (typeinfoIterator.hasNext()) { - - monitor.checkCanceled(); - - Symbol typeinfoSymbol = typeinfoIterator.next(); - Address typeinfoAddress = typeinfoSymbol.getAddress(); - - // skip the typeinfo symbols from the three special typeinfos - if (typeinfoAddress.equals(class_type_info) || - typeinfoAddress.equals(si_class_type_info) || - typeinfoAddress.equals(vmi_class_type_info)) { + // skip the typeinfo symbols from the three special typeinfos + if (typeinfo.isSpecialTypeinfo()) { continue; } - Namespace classNamespace = typeinfoSymbol.getParentNamespace(); + Namespace classNamespace = typeinfo.getNamespace(); RecoveredClass recoveredClass = getClass(classNamespace); if (recoveredClass == null) { - // this shoudln't be null at this point - if (DEBUG) { - Msg.debug(this, - "***Shouldn't be a null class here: " + classNamespace.getName()); - } - recoveredClass = createNewClass(classNamespace, false); - recoveredClasses.add(recoveredClass); + throw new IllegalArgumentException("RecoveredClass should already exist for " + classNamespace.getName(true)); } - else { - if (!recoveredClasses.contains(recoveredClass)) { - recoveredClasses.add(recoveredClass); - } - } - - Address specialTypeinfoRef = - extendedFlatAPI.getSingleReferencedAddress(typeinfoAddress); - if (specialTypeinfoRef == null) { - if (DEBUG) { - Msg.debug(this, - "No special typeinfo reference found. Cannot process typeinfo struct at " + - typeinfoAddress.toString()); - } - continue; - } - - if (!isSpecialTypeinfo(specialTypeinfoRef)) { - // check for EXTERNAL block and look for specialTypeinfoRef there - // if fix works, put external block error message and to contact us - if (!hasExternalBlock()) { - if (DEBUG) { - Msg.debug(this, - "Special typeinfo reference is not equal to one of the three special " + - "type infos. Cannot process typeinfo struct at " + - typeinfoAddress.toString()); - } - continue; - } - // use referenced vtable symbol name instead since when in EXTERNAL block - // since can't get at the typeinfo ref in that block - if (!isSpecialVtable(specialTypeinfoRef)) { - if (DEBUG) { - Msg.debug(this, - "Special typeinfo reference is not equal to one of the three special " + - "type infos. Cannot process typeinfo struct at " + - typeinfoAddress.toString()); - } - continue; - } - - } - - if (specialTypeinfoRef.equals(class_type_info) || - specialTypeinfoRef.equals(class_type_info_vtable)) { + + if (typeinfo.isClassTypeinfo()){ recoveredClass.setHasSingleInheritance(true); recoveredClass.setHasMultipleInheritance(false); recoveredClass.setHasMultipleVirtualInheritance(false); recoveredClass.setInheritsVirtualAncestor(false); // no parents so just add empty order and parent maps to the class maps - Map orderToParentMap = - new HashMap(); + Map orderToParentMap = new HashMap(); classToParentOrderMap.put(recoveredClass, orderToParentMap); @@ -410,18 +619,19 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // per docs those on this list are // classes containing only a single, public, non-virtual base at offset zero - if (specialTypeinfoRef.equals(si_class_type_info) || - specialTypeinfoRef.equals(si_class_type_info_vtable)) { - - RecoveredClass parentClass = getSiClassParent(typeinfoAddress); - if (parentClass == null) { - throw new Exception("Could not get si parent from typeinfoAddress " + - typeinfoAddress.toString()); + if (typeinfo.isSiClassTypeinfo()) { + + List baseTypeinfos = typeinfo.getBaseTypeinfos(); + if(baseTypeinfos.size() != 1) { + throw new IllegalArgumentException("SiClassTypeinfo " + classNamespace.getName(true) + " should have exactly one parent"); } - if (DEBUG) { - Msg.debug(this, - recoveredClass.getName() + " adding si parent " + parentClass.getName()); + GccTypeinfo siParentTypeinfo = baseTypeinfos.get(0).getBaseTypeinfo(); + RecoveredClass parentClass = getClass(siParentTypeinfo.getNamespace()); + + // parent isn't a known class - possibly is an external parent + if (parentClass == null) { + throw new IllegalArgumentException("RecoveredClass should already exist for " + siParentTypeinfo.getNamespace().getName(true)); } updateClassWithParent(parentClass, recoveredClass); @@ -430,10 +640,14 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { recoveredClass.setHasMultipleVirtualInheritance(false); parentClass.setIsPublicClass(true); recoveredClass.addParentToBaseTypeMapping(parentClass, false); + + // TODO: make method to check all ancestors not just parent + if(siParentTypeinfo.isVmiClassTypeinfo()) { + recoveredClass.setInheritsVirtualAncestor(true); + } // add order to parent and parent offset - Map orderToParentMap = - new HashMap(); + Map orderToParentMap = new HashMap(); orderToParentMap.put(0, parentClass); classToParentOrderMap.put(recoveredClass, orderToParentMap); @@ -442,28 +656,21 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { classToParentOffsetMap.put(recoveredClass, parentToOffsetMap); - if (!recoveredClasses.contains(parentClass)) { - recoveredClasses.add(parentClass); - } continue; } - if (specialTypeinfoRef.equals(vmi_class_type_info) || - specialTypeinfoRef.equals(vmi_class_type_info_vtable)) { + if (typeinfo.isVmiClassTypeinfo()) { - List parents = - addGccClassParentsFromVmiStruct(recoveredClass, typeinfoAddress); + List parents = addClassParentsAndFlagsForVmiClass(recoveredClass, typeinfo); if (parents.isEmpty()) { + Msg.debug(this, + "Could not get vmi parent from typeinfoAddress - removing class from list" + + typeinfoAddress.toString()); + recoveredClasses.remove(recoveredClass); continue; } - for (RecoveredClass parent : parents) { - monitor.checkCanceled(); - if (!recoveredClasses.contains(parent)) { - recoveredClasses.add(parent); - } - } } } @@ -473,146 +680,1052 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { /** * Method to process the primary vtable for each "vtable" label - * @throws Exception if Data cannot be created + * + * @throws CancelledException if cancelled + * @throws InvalidInputException if invalid symbol input + * + * @throws Exception if Data cannot be created */ - private void processVtables() throws Exception { + private List processVtables(List typeinfos) + throws CancelledException, InvalidInputException { - List listOfVtableSymbols = new ArrayList(); + List vtables = new ArrayList(); - // if dwarf loaded then get vtables using symbols - if (!isDwarfLoaded) { - listOfVtableSymbols = findVtablesUsingTypeinfoRefs(); - } - else { - listOfVtableSymbols = extendedFlatAPI.getListOfSymbolsInAddressSet( - program.getAddressFactory().getAddressSet(), VTABLE_LABEL, false); + if (typeinfos.isEmpty()) { + return vtables; } - List copyListOfVtableSymbols = new ArrayList(listOfVtableSymbols); + for (GccTypeinfo typeinfo : typeinfos) { + monitor.checkCancelled(); - Iterator vtableIterator = listOfVtableSymbols.iterator(); - - while (vtableIterator.hasNext()) { - - monitor.checkCanceled(); - - Symbol vtableSymbol = vtableIterator.next(); - Namespace vtableNamespace = vtableSymbol.getParentNamespace(); - Address vtableAddress = vtableSymbol.getAddress(); - - processVtable(vtableAddress, vtableNamespace, true, copyListOfVtableSymbols); - } - return; - } - - private List findVtablesUsingTypeinfoRefs() throws Exception { - - List vtableSymbols = new ArrayList(); - - List
typeinfoAddresses = getTypeinfoAddressesUsingSymbols(); - if (typeinfoAddresses.isEmpty()) { - return vtableSymbols; - } - - // find refs to typeinfo's that are not in functions, instructions, or typeinfo structs - // we only want ones that may be in vtables - List
typeinfoReferencesNotInTypeinfoStructs = - findTypeinfoReferencesNotInTypeinfoStructs(typeinfoAddresses); - - if (typeinfoReferencesNotInTypeinfoStructs.isEmpty()) { - return vtableSymbols; - } - - for (Address typeinfoRef : typeinfoReferencesNotInTypeinfoStructs) { - monitor.checkCanceled(); - - Address typeinfoAddress = extendedFlatAPI.getPointer(typeinfoRef); - - if (typeinfoAddress == null) { - continue; - } + Msg.debug(this, typeinfo.getNamespace().getName()); + Address typeinfoAddress = typeinfo.getAddress(); Structure typeinfoStructure = getTypeinfoStructure(typeinfoAddress); if (typeinfoStructure == null) { + Msg.error(this, "No structure at typeinfoAddress: " + typeinfoAddress); continue; } if (!isValidClassInfoStructure(typeinfoStructure)) { + Msg.error(this, "No typeinfo structure at typeinfoAddress: " + typeinfoAddress); continue; } + if (typeinfo.isSpecialTypeinfo) { + Msg.debug(this, "Skipping special typeinfos -- vtables already processed"); + continue; + } + + int numRefs = getNumberOfRefsByBaseTypeinfos(typeinfo, typeinfos); + + List
constructionVtables = new ArrayList
(); + Map map = getVtablesUsingTypeinfo(typeinfo); + Address mainVtable = findMainVtable(typeinfo, map, constructionVtables, numRefs); + + if (mainVtable != null) { + + Vtable vtable = processMainVtable(mainVtable, map.get(mainVtable)); + if (vtable == null) { + Msg.debug(this, + "MISSING expected vtable for simple class " + typeinfo.getNamespace().getName(true)); + continue; + } + + vtables.add(vtable); + applyVtableMarkup(vtable); + + + } + for (Address vtableAddress : constructionVtables) { + + Vtable constructionVtable = processVtable(vtableAddress, map.get(vtableAddress), true); + if (constructionVtable == null || !constructionVtable.isValid()) { + + Msg.debug(this, "Invalid construction vtable at " + vtableAddress); + continue; + } + vtables.add(constructionVtable); + + + } + + } + + List vtts = findVtts(vtables); + updateConstructionVtablesWithNamespace(vtts,vtables); + //TODO: update rest of vtt names my trying to match up with ones needing but missing VTT + + return vtables; + } + + private List findVtts(List vtables) throws CancelledException, InvalidInputException { + + List vtts = findVttsUsingSymbols(); + if (vtts.isEmpty()) { + // vtts = findVttsUsingReferences(vtables); + + vtts = findVttsWithoutSymbols(vtables); + + } + + // check vtts for run of pointers to other vtables /vfunctions and self and + // populate the vtt objects with the list of pointers in the vtt + // if possible update vtt with correct namespace + // TODO: add list of subVtt addrs to Vtt obj + updataVttPointers(vtts, vtables); + + return vtts; + } + + private void updateConstructionVtablesWithNamespace(List vtts, List vtables) throws CancelledException, InvalidInputException { + for (Vtable vtable : vtables) { + monitor.checkCancelled(); + + if (vtable.isConstructionVtable()) { + Vtt vtt = getVttContainingVtable(vtts, vtable); + Namespace vttNamespace = globalNamespace; + if (vtt != null) { + vttNamespace = vtt.getNamespace(); + } + else { + Msg.debug(this, "Cannot find vtt for vtable at " + vtable.getAddress()); + } + Namespace typeinfoNamespace = vtable.getReferencedTypeinfo().getNamespace(); + Namespace constructionNamespace = createConstructionNamespace(typeinfoNamespace, vttNamespace); + if (constructionNamespace != null) { + vtable.setNamespace(constructionNamespace); + } + else { + Msg.debug(this, "Cannot create construction namespace for vtable at " + vtable.getAddress()); + } + + } + applyVtableMarkup(vtable); + } + } + + private boolean isSelfReferencing(Address address) { + Address referencedAddress = getReferencedAddress(address); + if(referencedAddress == null) { + return false; + } + if(referencedAddress.equals(address)) { + return true; + } + return false; + } + + private List findVttsUsingSymbols() throws CancelledException{ + + List vtts = new ArrayList(); + SymbolIterator symbols = symbolTable.getSymbols("VTT"); + while(symbols.hasNext()) { + monitor.checkCancelled(); + + Symbol symbol = symbols.next(); + + Vtt vtt = new Vtt(symbol.getAddress(), symbol.getParentNamespace()); + vtts.add(vtt); + } + + return vtts; + } + + private List findVttsWithoutSymbols(List vtables) throws CancelledException, InvalidInputException { + + + List
vttStarts = findVttStarts(vtables); + + List vtts = new ArrayList(); + for (Address vttAddress : vttStarts) { + monitor.checkCancelled(); + + Namespace namespace = getVttNamespace(vttAddress, vtables); + + + Vtt vtt = new Vtt(vttAddress, namespace); + vtts.add(vtt); + symbolTable.createLabel(vttAddress, "VTT", namespace, SourceType.ANALYSIS); + api.setPlateComment(vttAddress, "VTT for " + namespace.getName(true)); + + } + return vtts; + } + + private Namespace getVttNamespace(Address vttAddress, List vtables) throws CancelledException { + + Namespace namespace = globalNamespace; + + Address referencedAddress = getReferencedAddress(vttAddress); + if(referencedAddress == null) { + throw new IllegalArgumentException("There should be a pointer here " + vttAddress); + } + + Vtable referencedVtable = getVtableContaining(vtables,referencedAddress); + if(referencedVtable != null && referencedVtable.isPrimary()) { + namespace = referencedVtable.getNamespace(); + } + return namespace; + } + + private List
findVttStarts(List vtables) throws CancelledException{ + + List
vttStarts = new ArrayList
(); + + List
addressesToCheck = new ArrayList
(); + + // make a list of possible vtt starting addresses + for(Vtable vtable : vtables) { + + monitor.checkCancelled(); + + addressesToCheck.add(vtable.getAddress().add(vtable.getLength())); + GccTypeinfo referencedTypeinfo = vtable.getReferencedTypeinfo(); + Address typeinfo = referencedTypeinfo.getAddress(); + Data typeinfoStruct = program.getListing().getDataAt(typeinfo); + if(typeinfoStruct == null) { + continue; + } + addressesToCheck.add(typeinfo.add(typeinfoStruct.getLength())); + } + + boolean keepChecking = true; + int numToCheck = addressesToCheck.size(); + while(keepChecking) { + for(Address possibleVttStart : addressesToCheck) { + + monitor.checkCancelled(); + + if(isPossibleVttStart(possibleVttStart, vtables, vttStarts)) { + vttStarts.add(possibleVttStart); + } + } + + addressesToCheck.removeAll(vttStarts); + if(addressesToCheck.size() == numToCheck) { + keepChecking = false; + } + numToCheck = addressesToCheck.size(); + } + + return vttStarts; + + } + + private Vtt getVttContainingVtable(List vtts, Vtable vtable) throws CancelledException { + + for (Vtt vtt : vtts) { + monitor.checkCancelled(); + + if (vtt.containsPointer(vtable.getAddress())) { + return vtt; + } + if (vtable.hasVfunctions() && vtt.containsPointer(vtable.getVfunctionTop())) { + return vtt; + } + } + return null; + } + + private void updataVttPointers(List vtts, List vtables) throws CancelledException { + + // make list of all vtable tops and vftable tops + List
vtableAndVftableAddrs = getListOfVtableAndVftableTops(vtables); + List
vttStarts = getVttAddresses(vtts); + + + // if vtt references one of the vtable or vftable tops OR if it references + // itself add the ref'd addr to the list in vtt obj + for (Vtt vtt : vtts) { + monitor.checkCancelled(); + Address pointerAddress = vtt.getAddress(); + Address referencedAddress = getReferencedAddress(pointerAddress); + while (referencedAddress != null && (vtableAndVftableAddrs.contains(referencedAddress) + || referencedAddress.equals(vtt.getAddress()) || isSelfReferencing(pointerAddress) || vttStarts.contains(referencedAddress))) { + vtt.addPointerToList(referencedAddress); + pointerAddress = pointerAddress.add(defaultPointerSize); + referencedAddress = getReferencedAddress(pointerAddress); + } + } + } + + private List
getVtableAddresses(List vtables) throws CancelledException { + List
vtableStarts = new ArrayList
(); + + for (Vtable vtable : vtables) { + monitor.checkCancelled(); + + vtableStarts.add(vtable.getAddress()); + } + return vtableStarts; + } + + private List
getVttAddresses(List vtts) throws CancelledException { + List
vttStarts = new ArrayList
(); + + for (Vtt vtt : vtts) { + monitor.checkCancelled(); + + vttStarts.add(vtt.getAddress()); + } + return vttStarts; + } + + + private boolean isPossibleVttStart(Address address, List vtables, List
knownVtts) throws CancelledException { + + // make list of all vtable tops and vftable tops + List
vtableAndVftableAddrs = getListOfVtableAndVftableTops(vtables); + + if(isSelfReferencing(address)) { + return true; + } + + Address referencedAddress = getReferencedAddress(address); + if(referencedAddress != null && (vtableAndVftableAddrs.contains(referencedAddress) || knownVtts.contains(referencedAddress))){ + return true; + } + + return false; + + } +private Address getReferencedAddress(Address address) { + + int addressSize = address.getSize(); + Memory memory = program.getMemory(); + try { + + if (addressSize == 32) { + long offset32 = memory.getInt(address); + Address newAddr = address.getNewAddress(offset32); + if(memory.contains(newAddr)) { + return newAddr; + } + return null; + + } + else if (addressSize == 64) { + + long offset64 = memory.getLong(address); + Address newAddr = address.getNewAddress(offset64); + if(memory.contains(newAddr)) { + return newAddr; + } + return null; + + } + else { + return null; + } + } + catch (MemoryAccessException e) { + return null; + } + } + + private List
getListOfVtableAndVftableTops(List vtables) throws CancelledException { + // make list of all vtable tops and vftable tops + List
vtableAndVftableAddrs = new ArrayList
(); + for (Vtable vtable : vtables) { + monitor.checkCancelled(); + + vtableAndVftableAddrs.add(vtable.getAddress()); + if (vtable.hasVfunctions()) { + vtableAndVftableAddrs.add(vtable.getVfunctionTop()); + } + + vtableAndVftableAddrs.addAll(getListOfVtableAndVftableTops(vtable.getInternalVtables())); + } + return vtableAndVftableAddrs; + } + + private Vtable processMainVtable(Address vtableAddress, GccTypeinfoRef typeinfoRef) throws CancelledException { + Vtable vtable = processVtable(vtableAddress, typeinfoRef, false); + if (vtable == null || !vtable.isValid()) { + + Msg.debug(this, "Invalid vtable at " + vtableAddress); + return null; + } + return vtable; + } + + private void applyVtableMarkup(Vtable vtable) throws InvalidInputException { + + boolean hasKnownConstructionSymbol = false; + if (vtable.isConstructionVtable()) { + Symbol vtableSymbol = symbolTable.getPrimarySymbol(vtable.getAddress()); + if (vtableSymbol != null && !vtableSymbol.getParentNamespace().isGlobal()) { + hasKnownConstructionSymbol = true; + vtable.setNamespace(vtableSymbol.getParentNamespace()); + } + } + createVtableLabel(vtable); + createVtableComment(vtable); + createVfunctionSymbol(vtable); + + for (Vtable internalVtable : vtable.getInternalVtables()) { + + if (hasKnownConstructionSymbol) { + internalVtable.setNamespace(vtable.getNamespace()); + } + createVtableLabel(internalVtable); + createVtableComment(internalVtable); + createVfunctionSymbol(internalVtable); + } + } + + + /** + * method to find the main vtable for the given typeinfo and if any, add the + * construction ones to the passed in list + * + * @param typeinfo + * @param constructionVtables + * @return address of main vtable for this class + * @throws CancelledException + */ + + private Address findMainVtable(GccTypeinfo typeinfo, Map map, + List
constructionVtables, int numBaseRefs) throws CancelledException { + + List
vtableList = new ArrayList
(map.keySet()); + + // if any have known symbols then return + // can be single main vtable, main vtable and one or more construction vtables, + // or no main vtable and one or + // more construction vtables + Address mainVtable = getMainVtableUsingSymbols(vtableList, constructionVtables); + if (mainVtable != null || !constructionVtables.isEmpty()) { + return mainVtable; + } + + + // no const vtables for this typeinfo if only one in list + if (vtableList.size() == 1 && (typeinfo.isClassTypeinfo() || typeinfo.isSiClassTypeinfo()) + && typeinfo.getNumDirectVirtualBases() == 0) { + return vtableList.get(0); + } + + // if more than one add all to the construction list then remove the main one + // when found + constructionVtables.addAll(vtableList); + + + Map> vtableRefsMap = createMapOfVtableRefs(vtableList); + Map> vftableRefsMap = createMapOfVftableRefs(vtableList, map); + + // if only one vtable has have all func refs it is main one + mainVtable = findMainVtableOnlyFunctionRefs(vtableRefsMap, vftableRefsMap); + if (mainVtable != null) { + constructionVtables.remove(mainVtable); + return mainVtable; + } + // if only one vtable has function refs then it is the main vtable + mainVtable = findMainVtableUsingFunctionRefs(vtableRefsMap, vftableRefsMap); + if (mainVtable != null) { + constructionVtables.remove(mainVtable); + return mainVtable; + } + // see if there are no refs for any of them - new way + mainVtable = findMainVtableNoRefs(vtableRefsMap, vftableRefsMap); + if (mainVtable != null) { + constructionVtables.remove(mainVtable); + return mainVtable; + } + + + if(vtableList.size() == 1) { + if(numBaseRefs == 0) { + return vtableList.get(0); + } + constructionVtables.add(vtableList.get(0)); + return null; + + } + + // if still no clear winner and there is only one on list try using internal vtables + // make a temp vtable to pull out any internal vtables and try to test them + if (vtableList.size() == 1) { + Address vtableAddress = vtableList.get(0); + GccTypeinfoRef typeinfoRef = map.get(vtableAddress); + Vtable vtable = new Vtable(program, vtableAddress, typeinfoRef, false, false, false, monitor); + if(!vtable.isValid()) { + return null; + } + List internalVtables = vtable.getInternalVtables(); + List
internalVtableAddrs = new ArrayList
(); + for(Vtable internalVtable : internalVtables) { + Address internalVtableAddress = internalVtable.getAddress(); + internalVtableAddrs.add(internalVtableAddress); + + Address internalTypinfoRef = internalVtable.getTypeinfoRefAddress(); + GccTypeinfoRef gccTypeinfoRef = map.get(internalVtableAddress); + if (gccTypeinfoRef == null) { + map.put(internalVtableAddress, new GccTypeinfoRef(internalTypinfoRef, typeinfo, true)); + } else { + if (gccTypeinfoRef.getAddress().compareTo(internalTypinfoRef) > 0) { + map.put(internalVtableAddress, new GccTypeinfoRef(internalTypinfoRef, typeinfo, true)); + } + } + + } + if (internalVtables.size() > 0) { + Map> internalVtableRefsMap = createMapOfVtableRefs(internalVtableAddrs); + Map> internalVftableRefsMap = createMapOfVftableRefs(internalVtableAddrs, map); + + // this isn't the mainVtable - just using to test if functions are ref + mainVtable = findMainVtableUsingFunctionRefs(internalVtableRefsMap, internalVftableRefsMap); + if (mainVtable != null) { + mainVtable = vtableAddress; + constructionVtables.remove(mainVtable); + return mainVtable; + } + } + } + + // no main vtable - all construction vtables + return null; + } + + + private int getNumberOfRefsByBaseTypeinfos(GccTypeinfo typeinfo, List typeinfos) throws CancelledException { + + int numRefs = 0; + for(GccTypeinfo typinfo : typeinfos) { + monitor.checkCancelled(); + + if(typinfo.isSpecialTypeinfo()) { + continue; + } + + if(!typinfo.isVmiClassTypeinfo()) { + continue; + } + + List baseTypeinfos = typinfo.getBaseTypeinfos(); + for(BaseTypeinfo baseTypeinfo : baseTypeinfos) { + monitor.checkCancelled(); + + if(baseTypeinfo.getBaseTypeinfo().equals(typeinfo)){ + numRefs++; + } + } + } + return numRefs; + } + + private Map> createMapOfVtableRefs(List
vtableList) throws CancelledException { + + Map> map = new HashMap>(); + for (Address vtableAddr : vtableList) { + monitor.checkCancelled(); + + map.put(vtableAddr, getAllReferencesTo(vtableAddr)); + } + + return map; + } + + private Map> createMapOfVftableRefs(List
vtableList, + Map map) throws CancelledException { + + Map> refmap = new HashMap>(); + for (Address vtableAddr : vtableList) { + monitor.checkCancelled(); + + GccTypeinfoRef typeinfoRef = map.get(vtableAddr); + Address topOfVfunctions = typeinfoRef.getAddress().add(defaultPointerSize); + + // null means no vfunctions for this vtable + if (!isVirtualFunctionTable(topOfVfunctions)) { + refmap.put(vtableAddr, null); + continue; + } + + refmap.put(vtableAddr, getAllReferencesTo(topOfVfunctions)); + } + + return refmap; + } + + private Address findMainVtableOnlyFunctionRefs(Map> vtableRefsMap, + Map> vftableRefsMap) throws CancelledException { + + List
possibleMains = new ArrayList
(); + + Set
vtables = vtableRefsMap.keySet(); + + for (Address vtableAddr : vtables) { + monitor.checkCancelled(); + + List
refsToVtable = vtableRefsMap.get(vtableAddr); + + if (hasAllFunctionRefs(refsToVtable)) { + possibleMains.add(vtableAddr); + continue; + } + + // use typenfo ref to get top of vfunctions (if there are any) + List
refsToVftable = vftableRefsMap.get(vtableAddr); + + if (refsToVftable != null) { // null if no vftable for this vtable + + if (hasAllFunctionRefs(refsToVftable)) { + possibleMains.add(vtableAddr); + continue; + } + } + } + if (possibleMains.size() == 1) { + return possibleMains.get(0); + } + + return null; + } + + private Address findMainVtableUsingFunctionRefs(Map> vtableRefsMap, + Map> vftableRefsMap) throws CancelledException { + + List
possibleMains = new ArrayList
(); + + Set
vtables = vtableRefsMap.keySet(); + + for (Address vtableAddr : vtables) { + monitor.checkCancelled(); + + List
refsToVtable = vtableRefsMap.get(vtableAddr); + + if (hasAnyFunctionRefs(refsToVtable)) { + possibleMains.add(vtableAddr); + continue; + } + + // use typenfo ref to get top of vfunctions (if there are any) + List
refsToVftable = vftableRefsMap.get(vtableAddr); + + if (refsToVftable != null) { // null if no vftable for this vtable + + if (hasAnyFunctionRefs(refsToVftable)) { + possibleMains.add(vtableAddr); + continue; + } + } + } + if (possibleMains.size() == 1) { + return possibleMains.get(0); + } + + return null; + } + + private Address findMainVtableNoRefs(Map> vtableRefsMap, + Map> vftableRefsMap) throws CancelledException { + + List
possibleMains = new ArrayList
(); + + Set
vtables = vtableRefsMap.keySet(); + + for (Address vtableAddr : vtables) { + monitor.checkCancelled(); + + List
refsToVtable = vtableRefsMap.get(vtableAddr); + + if (!refsToVtable.isEmpty()) { + continue; + } + + // use typenfo ref to get top of vfunctions (if there are any) + List
refsToVftable = vftableRefsMap.get(vtableAddr); + + if (refsToVftable == null || refsToVftable.isEmpty()) { // null if no vftable for this vtable + possibleMains.add(vtableAddr); + continue; + + } + } + if (possibleMains.size() == 1) { + return possibleMains.get(0); + } + + return null; + } + + private boolean isVirtualFunctionTable(Address address) throws CancelledException { + + if (isPossibleFunctionPointer(address)) { + return true; + } + + MemoryBlock currentBlock = program.getMemory().getBlock(address); + + // may start with null pointers + while (isPossibleNullPointer(address)) { + monitor.checkCancelled(); + + if (!currentBlock.contains(address)) { + return false; + } + address = address.add(defaultPointerSize); + } + + // if item directly after nulls is function ptr then is function table + if (isPossibleFunctionPointer(address)) { + return true; + } + return false; + + } + + private Address getMainVtableUsingSymbols(List
vtableAddresses, List
constructionVtables) + throws CancelledException { + + List
mainVtableCandidates = new ArrayList
(); + for (Address vtableAddress : vtableAddresses) { + monitor.checkCancelled(); + + Symbol primarySymbol = symbolTable.getPrimarySymbol(vtableAddress); + if (primarySymbol != null && primarySymbol.getName().equals(VTABLE_LABEL)) { + mainVtableCandidates.add(vtableAddress); + } + if (primarySymbol != null && primarySymbol.getName().equals("construction-" + VTABLE_LABEL)) { + constructionVtables.add(vtableAddress); + } + } + + if (mainVtableCandidates.size() != 1) { + return null; + } + + return mainVtableCandidates.get(0); + } + + + private Map getVtablesUsingTypeinfo(GccTypeinfo typeinfo) throws CancelledException { + + Map map = new HashMap(); + Set
typeinfoRefs = findTypeinfoRefsPossiblyInVtables(typeinfo); + + for (Address typeinfoRef : typeinfoRefs) { + monitor.checkCancelled(); + // get top of vtable Address vtableAddress = getPrimaryVtableAddress(typeinfoRef); + + // no vtable associated with this typeinfo if (vtableAddress == null) { continue; } - // create symbol - Symbol typeinfoSymbol = api.getSymbolAt(typeinfoAddress); - if (typeinfoSymbol == null) { - continue; - } - if (!typeinfoSymbol.getName().equals("typeinfo")) { - continue; + GccTypeinfoRef gccTypeinfoRef = map.get(vtableAddress); + if (gccTypeinfoRef == null) { + map.put(vtableAddress, new GccTypeinfoRef(typeinfoRef, typeinfo, true)); + } else { + if (gccTypeinfoRef.getAddress().compareTo(typeinfoRef) > 0) { + map.put(vtableAddress, new GccTypeinfoRef(typeinfoRef, typeinfo, true)); + } } - // check for construction table and make new namespace if so - Namespace classNamespace = typeinfoSymbol.getParentNamespace(); - - if (classNamespace.equals(globalNamespace)) { - throw new Exception("typeinfo has global namespace " + typeinfoAddress); - } - - Symbol vtableSymbol = symbolTable.createLabel(vtableAddress, VTABLE_LABEL, - classNamespace, SourceType.ANALYSIS); - vtableSymbols.add(vtableSymbol); - - api.setPlateComment(vtableAddress, "vtable for " + classNamespace.getName(true)); } - return vtableSymbols; + return map; + } + + private boolean hasAllFunctionRefs(Collection
refs) throws CancelledException { + + if (refs == null || refs.isEmpty()) { + return false; + } + + for (Address ref : refs) { + monitor.checkCancelled(); + if (ref.isExternalAddress()) { + continue; + } + Function function = functionManager.getFunctionContaining(ref); + if (function == null) { + return false; + } + } + return true; + } + + private boolean hasAnyFunctionRefs(Collection
refs) throws CancelledException { + + if (refs == null || refs.isEmpty()) { + return false; + } + for (Address ref : refs) { + monitor.checkCancelled(); + + if (ref.isExternalAddress()) { + continue; + } + Function function = functionManager.getFunctionContaining(ref); + if (function != null) { + return true; + } + } + return false; + } + + private Vtable getVtable(List vtables, Namespace classNamespace) throws CancelledException { + + for (Vtable vtable : vtables) { + monitor.checkCancelled(); + + if (vtable.getNamespace().equals(classNamespace) && vtable.isPrimary() && !vtable.isConstructionVtable()) { + return vtable; + } + } + return null; + } + + private Vtable getVtable(List vtables, Address address) throws CancelledException { + + for (Vtable vtable : vtables) { + monitor.checkCancelled(); + + if (vtable.getAddress().equals(address)) { + return vtable; + } + } + return null; + } + + private Vtable getVtableContaining(List vtables, Address address) throws CancelledException { + for (Vtable vtable : vtables) { + + monitor.checkCancelled(); + + AddressSet vtableAddrs = new AddressSet(vtable.getAddress(), vtable.getAddress().add(vtable.getLength())); + + if (vtableAddrs.contains(address)) { + return vtable; + } + } + return null; + } + + + private void createVtableComment(Vtable vtable) { + + if (!vtable.isPrimary()) { + return; + } + + Address vtableAddress = vtable.getAddress(); + Namespace classNamespace = vtable.getNamespace(); + + if (classNamespace == null) { + return; + } + + String plateComment = api.getPlateComment(vtableAddress); + if (plateComment != null && plateComment.contains(VTABLE_LABEL) + && plateComment.contains(classNamespace.getName())) { + return; + } + + String constructionString = ""; + if (vtable.isConstructionVtable() != null && vtable.isConstructionVtable()) { + constructionString = "construction-"; + } + String vtableComment = VTABLE_LABEL; + + api.setPlateComment(vtableAddress, constructionString + vtableComment + " for " + classNamespace.getName(true)); } + private void createVtableLabel(Vtable vtable) throws InvalidInputException { + + Address vtableAddress = vtable.getAddress(); + + Namespace classNamespace = vtable.getNamespace(); + + if (classNamespace == null) { + return; + } + + String vtableLabel = VTABLE_LABEL; + + Symbol primarySymbol = symbolTable.getPrimarySymbol(vtableAddress); + if (primarySymbol != null && primarySymbol.getName().contains(vtableLabel) + && primarySymbol.getParentNamespace().equals(classNamespace)) { + return; + } + + String constructionString = ""; + if (vtable.isConstructionVtable() != null && vtable.isConstructionVtable()) { + constructionString = "construction-"; + } + + String internalString = ""; + if (!vtable.isPrimary()) { + internalString = "internal_"; + } + + symbolTable.createLabel(vtableAddress, internalString + constructionString + VTABLE_LABEL, classNamespace, + SourceType.ANALYSIS); + + } + + private void createVfunctionSymbol(Vtable vtable) throws InvalidInputException { + + if (!vtable.hasVfunctions()) { + return; + } + + Namespace classNamespace = vtable.getNamespace(); + + if (classNamespace == null) { + return; + } + + String constructionString = ""; + if (vtable.isConstructionVtable() != null && vtable.isConstructionVtable()) { + constructionString = "construction-"; + } + + String internalString = ""; + if (!vtable.isPrimary()) { + internalString = "internal_"; + } + + symbolTable.createLabel(vtable.getVfunctionTop(), internalString + constructionString + VFTABLE_LABEL, + classNamespace, SourceType.ANALYSIS); + + } + + List getTypeinfosByType(List typeinfoSymbols, String typeinfoType) throws CancelledException { + + List subsetByType = new ArrayList(); + + for (Symbol symbol : typeinfoSymbols) { + monitor.checkCancelled(); + + String type = typeinfoToStructuretypeMap.get(symbol.getAddress()); + if (type.equals(typeinfoType)) { + subsetByType.add(symbol); + } + } + + return subsetByType; + } + + private Address getPrimaryVtableAddress(Address typeinfoRef) throws CancelledException { + if (typeinfoRef == null) { + return null; + } + // get the data containing the typeinfo reference + Data dataContaining = extendedFlatAPI.getDataContaining(typeinfoRef); + if (dataContaining != null) { + + // get the top address of the containing data + Address dataAddress = dataContaining.getAddress(); + + // if it has a vtable label then return the data address + boolean hasVtableLabel = hasSymbolWithName(dataAddress, VTABLE_LABEL) + || hasSymbolWithName(dataAddress, CONSTRUCTION_VTABLE_LABEL); + if (hasVtableLabel) { + return dataAddress; + } + + // if data has imported symbol and no symbols named vtable then it isn't a + // vtable + // checking this way checks both imported actual symbols and imported mangled + // symbols with analysis demangled symbols + if (hasImportedSymbol(dataAddress) && !hasVtableLabel) { + return null; + } + + } + // check the long just before and if not a zero then continue since the rest // are internal vtables and will get processed when the main one does - Address longBeforeTypeinfoRef = getAddress(typeinfoRef, 0 - defaultPointerSize); + Address offsetToTop = getAddress(typeinfoRef, 0 - defaultPointerSize); - // if this address doesn't exist then continue since not a valid vtable - if (longBeforeTypeinfoRef == null) { - return null; - } - // check for appropriately sized long that is value 0 to make sure the + // check for appropriately sized long that is value 0 to make sure the // vtable the typeinfo ref is in is the main one and skip otherwise since non-zero // ones are internal vtables that will get processed with the main one - if (!extendedFlatAPI.hasNumZeros(longBeforeTypeinfoRef, defaultPointerSize)) { + if (!extendedFlatAPI.hasNumZeros(offsetToTop, defaultPointerSize)) { return null; } - Address vtableAddress = longBeforeTypeinfoRef; - MemoryBlock currentBlock = program.getMemory().getBlock(typeinfoRef); - + // start with last verified part of possible vtable and continue going backwards + // until top of vtable is found // stop if top of mem block // stop if bytes are an address // stop if referenced - // are they ever zero - not that i have seen so far in the last vftable - // if pointer to something or valid address - // or is in a structure - Address nextAddress = getAddress(vtableAddress, 0 - defaultPointerSize); - while (nextAddress != null && - program.getMemory().getBlock(nextAddress).equals(currentBlock) && - getPointerToDefinedMemory(nextAddress) == null) { - vtableAddress = nextAddress; - nextAddress = getAddress(vtableAddress, 0 - defaultPointerSize); + // are they ever zero - not that i have seen so far in the last vftable + // if pointer to something or valid address or is in a structure + Address vtableAddress = offsetToTop; + MemoryBlock currentBlock = program.getMemory().getBlock(typeinfoRef); + + while (vtableAddress != null) { + + boolean hasVtableLabel = hasSymbolWithName(vtableAddress, VTABLE_LABEL) + || hasSymbolWithName(vtableAddress, CONSTRUCTION_VTABLE_LABEL); + if (hasVtableLabel) { + return vtableAddress; + } + + // if address has imported symbol and no symbols named vtable then it isn't a + // vtable + // checking this way checks both imported actual symbols and imported mangled + // symbols with analysis demangled symbols + if (hasImportedSymbol(vtableAddress) && !hasVtableLabel) { + return null; + } + + if (getPointerToDefinedMemory(vtableAddress) != null) { + return vtableAddress.add(defaultPointerSize); + } + + MemoryBlock memoryBlock = program.getMemory().getBlock(vtableAddress); + if (memoryBlock == null || !memoryBlock.equals(currentBlock)) { + return vtableAddress.add(defaultPointerSize); + } + + Data data = api.getDataContaining(vtableAddress); + if (data != null && !data.getDataType().getName().contains("undefined")) { + return vtableAddress.add(defaultPointerSize); + } + + vtableAddress = getAddress(vtableAddress, 0 - defaultPointerSize); } - return vtableAddress; + return null; } + private boolean hasImportedSymbol(Address address) throws CancelledException { + + Symbol[] symbols = symbolTable.getSymbols(address); + for (Symbol symbol : symbols) { + monitor.checkCancelled(); + if (symbol.getSource() == SourceType.IMPORTED) { + return true; + } + } + return false; + } + + private boolean hasSymbolWithName(Address address, String name) throws CancelledException { + + Symbol[] symbols = symbolTable.getSymbols(address); + for (Symbol symbol : symbols) { + monitor.checkCancelled(); + if (symbol.getName().equals(name)) { + return true; + } + } + return false; + } + private Address getPointerToDefinedMemory(Address address) { Address pointer = extendedFlatAPI.getPointer(address); @@ -643,30 +1756,18 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { return false; } - private Namespace createConstructionNamespace(Symbol vtableSymbol, Symbol vttSymbol) - throws Exception { + private Namespace createConstructionNamespace(Namespace namespaceIn, Namespace vttNamespace) { - Namespace vtableNamespace = vtableSymbol.getParentNamespace(); - - Namespace inNamespace = vttSymbol.getParentNamespace(); - String name = vtableNamespace.getName() + "-in-" + inNamespace.getName(true); - - List namespacesByPath = - NamespaceUtils.getNamespaceByPath(program, vtableNamespace, name); - - if (namespacesByPath.isEmpty()) { - - Namespace newNamespace = NamespaceUtils.createNamespaceHierarchy(name, vtableNamespace, - program, SourceType.ANALYSIS); - return newNamespace; + String name = namespaceIn.getName() + "-in-" + vttNamespace.getName(true); + Namespace newNamespace; + try { + newNamespace = NamespaceUtils.createNamespaceHierarchy(name, namespaceIn.getParentNamespace(), program, + SourceType.ANALYSIS); + } catch (InvalidInputException e) { + return null; } - if (namespacesByPath.size() == 1) { - return namespacesByPath.get(0); - } - - throw new Exception( - "More than one namespace " + vtableNamespace.getName(true) + " " + name); + return newNamespace; } private Structure getTypeinfoStructure(Address typeinfoAddress) { @@ -681,7 +1782,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } - public List
findTypeinfoReferencesNotInTypeinfoStructs(List
typeinfoAddresses) + public Map> findTypeinfoReferencesNotInTypeinfoStructsOld(List
typeinfoAddresses) throws CancelledException { MemoryBytePatternSearcher searcher = new MemoryBytePatternSearcher("Typeinfo References"); @@ -690,39 +1791,203 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { AddressSetView initializedSet = program.getMemory().getAllInitializedAddressSet(); AddressRangeIterator addressRanges = initializedSet.getAddressRanges(); while (addressRanges.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); AddressRange addressRange = addressRanges.next(); searchSet.add(addressRange.getMinAddress(), addressRange.getMaxAddress()); } - List
validTypeinfoRefs = new ArrayList
(); + Map> validTypeinfoRefMap = new HashMap>(); + + for (Address typeinfoAddress : typeinfoAddresses) { + monitor.checkCancelled(); - Iterator
typeinfoIterator = typeinfoAddresses.iterator(); - while (typeinfoIterator.hasNext()) { - monitor.checkCanceled(); - Address typeinfoAddress = typeinfoIterator.next(); // 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, validTypeinfoRefMap, typeinfoAddress, bytes, monitor); } searcher.search(program, searchSet, monitor); - return validTypeinfoRefs; + return validTypeinfoRefMap; + } + + public Map> findAllDirectRefs() throws CancelledException { + + MemoryBytePatternSearcher searcher = new MemoryBytePatternSearcher("Direct References"); + + AddressSet searchSet = new AddressSet(); + AddressSetView initializedSet = program.getMemory().getAllInitializedAddressSet(); + AddressRangeIterator addressRanges = initializedSet.getAddressRanges(); + while (addressRanges.hasNext()) { + monitor.checkCancelled(); + AddressRange addressRange = addressRanges.next(); + + searchSet.add(addressRange.getMinAddress(), addressRange.getMaxAddress()); + } + Map> directRefMap = new HashMap>(); + + AddressIterator addrIter = initializedSet.getAddresses(initializedSet.getMinAddress(), true); + while (addrIter.hasNext()) { + monitor.checkCancelled(); + Address address = addrIter.next(); + // check direct refs to see if they are in undefined area or not in function + byte[] bytes = ProgramMemoryUtil.getDirectAddressBytes(program, address); + + addByteSearchPatternDirRefs(searcher, directRefMap, address, bytes, monitor); + + } + searcher.search(program, searchSet, monitor); + return directRefMap; } /** - * Method to add a search pattern, to the searcher, for the set of bytes representing a typeinfo - * address - * @param searcher the MemoryBytePatternSearcher - * @param typeinfoRefs a list typeinfo reference addresses that are not contained - * in a function, instruction, or a typeinfo structure - * @param typeinfoAddress the given typeinfo address - * @param bytes the bytes to search for - * @param taskMonitor a cancellable monitor + * Method to add a search pattern, to the searcher, for the set of bytes + * representing a typeinfo address + * + * @param searcher the MemoryBytePatternSearcher + * @param typeinfoRefMap a map of typeinfoAddress to Set of typeinfo reference + * addresses that are not contained in a function, + * instruction, or a typeinfo structure + * @param address the given typeinfo address + * @param bytes the bytes to search for + * @param taskMonitor a cancellable monitor */ - private void addByteSearchPattern(MemoryBytePatternSearcher searcher, - List
typeinfoRefs, Address typeinfoAddress, byte[] bytes, - TaskMonitor taskMonitor) { + private void addByteSearchPatternDirRefs(MemoryBytePatternSearcher searcher, + Map> typeinfoRefMap, Address address, byte[] bytes, TaskMonitor taskMonitor) { + + // no pattern bytes. + if (bytes == null) { + return; + } + + // Each time a match for this byte pattern ... + GenericMatchAction
action = new GenericMatchAction
(address) { + @Override + public void apply(Program prog, Address addr, Match match) { + + Set
dirRefs = typeinfoRefMap.get(address); + if (dirRefs == null) { + dirRefs = new HashSet
(); + } + dirRefs.add(addr); + typeinfoRefMap.put(address, dirRefs); + + } + + }; + + // create a Pattern of the bytes and the MatchAction to perform upon a match + GenericByteSequencePattern
genericByteMatchPattern = new GenericByteSequencePattern<>(bytes, action); + + searcher.addPattern(genericByteMatchPattern); + + } + + public Map> findTypeinfoReferencesNotInTypeinfoStructs(List typeinfos) + throws CancelledException { + + MemoryBytePatternSearcher searcher = new MemoryBytePatternSearcher("Typeinfo References"); + + AddressSet searchSet = new AddressSet(); + AddressSetView initializedSet = program.getMemory().getAllInitializedAddressSet(); + AddressRangeIterator addressRanges = initializedSet.getAddressRanges(); + while (addressRanges.hasNext()) { + monitor.checkCancelled(); + AddressRange addressRange = addressRanges.next(); + searchSet.add(addressRange.getMinAddress(), addressRange.getMaxAddress()); + } + Map> validTypeinfoRefMap = new HashMap>(); + + for (GccTypeinfo typeinfo : typeinfos) { + monitor.checkCancelled(); + Address typeinfoAddress = typeinfo.getAddress(); + // check direct refs to see if they are in undefined area or not in function + byte[] bytes = ProgramMemoryUtil.getDirectAddressBytes(program, typeinfoAddress); + + addByteSearchPattern(searcher, validTypeinfoRefMap, typeinfoAddress, bytes, monitor); + + } + searcher.search(program, searchSet, monitor); + return validTypeinfoRefMap; + } + + /** + * Method to find references to the given typeinfos that are possibly ref'd by + * vtables (ie not in functions, other data, etc... and create a map + * typeinfoAddress to Set
refs possibly in vtable + * + * @param typeinfos list of GccTypeinfo's + * @return map + * @throws CancelledException + */ + public Map> findTypeinfoRefsPossiblyInVtables(List typeinfos) + throws CancelledException { + + Map> typeinfoRefMap = new HashMap>(); + + for (GccTypeinfo typeinfo : typeinfos) { + monitor.checkCancelled(); + + Set
typeinfoRefs = findTypeinfoRefsPossiblyInVtables(typeinfo); + + // don't add if no refs in possible vtables + if (typeinfoRefs.isEmpty()) { + continue; + } + typeinfoRefMap.put(typeinfo.getAddress(), typeinfoRefs); + } + return typeinfoRefMap; + } + + public Set
findTypeinfoRefsPossiblyInVtables(GccTypeinfo typeinfo) throws CancelledException { + + Address typeinfoAddr = typeinfo.getAddress(); + Set
typeinfoRefsPossiblyInVtables = new HashSet
(); + + Set
typeinfoRefs = directRefMap.get(typeinfoAddr); + + // return emtpy list if no entry in map for given typeinfoAddr + if (typeinfoRefs == null) { + return typeinfoRefsPossiblyInVtables; + } + + for (Address typeinfoRef : typeinfoRefs) { + + Function functionContainingTypeinfoRef = program.getListing().getFunctionContaining(typeinfoRef); + if (functionContainingTypeinfoRef != null) { + continue; + } + + Instruction instructionContainingAddr = program.getListing().getInstructionContaining(typeinfoRef); + if (instructionContainingAddr != null) { + continue; + } + + Data dataContainingTypeinfoRef = program.getListing().getDefinedDataContaining(typeinfoRef); + + if (dataContainingTypeinfoRef == null + || (dataContainingTypeinfoRef != null && !isTypeinfoStruct(dataContainingTypeinfoRef))) { + + typeinfoRefsPossiblyInVtables.add(typeinfoRef); + } + } + + return typeinfoRefsPossiblyInVtables; + } + + /** + * Method to add a search pattern, to the searcher, for the set of bytes + * representing a typeinfo address + * + * @param searcher the MemoryBytePatternSearcher + * @param typeinfoRefMap a map of typeinfoAddress to Set of typeinfo reference + * addresses that are not contained in a function, + * instruction, or a typeinfo structure + * @param typeinfoAddress the given typeinfo address + * @param bytes the bytes to search for + * @param taskMonitor a cancellable monitor + */ + private void addByteSearchPattern(MemoryBytePatternSearcher searcher, Map> typeinfoRefMap, + Address typeinfoAddress, byte[] bytes, TaskMonitor taskMonitor) { // no pattern bytes. if (bytes == null) { @@ -734,24 +1999,29 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { @Override public void apply(Program prog, Address addr, Match match) { - Function functionContainingTypeinfoRef = - prog.getListing().getFunctionContaining(addr); + Function functionContainingTypeinfoRef = prog.getListing().getFunctionContaining(addr); Data dataContainingTypeinfoRef = prog.getListing().getDefinedDataContaining(addr); - Instruction instructionContainingAddr = - prog.getListing().getInstructionContaining(addr); + Instruction instructionContainingAddr = prog.getListing().getInstructionContaining(addr); // check the direct references found with the searcher // if not in function but is an instruction then create the function // otherwise, add to the list to report to user - if (functionContainingTypeinfoRef == null && instructionContainingAddr == null && - dataContainingTypeinfoRef == null) { - typeinfoRefs.add(addr); + boolean add = false; + if (functionContainingTypeinfoRef == null && instructionContainingAddr == null + && dataContainingTypeinfoRef == null) { + add = true; + } else if (dataContainingTypeinfoRef != null && !isTypeinfoStruct(dataContainingTypeinfoRef)) { + add = true; } - else if (dataContainingTypeinfoRef != null && - !isTypeinfoStruct(dataContainingTypeinfoRef)) { + if (add) { + Set
typeinfoRefs = typeinfoRefMap.get(typeinfoAddress); + if (typeinfoRefs == null) { + typeinfoRefs = new HashSet
(); + } typeinfoRefs.add(addr); + typeinfoRefMap.put(typeinfoAddress, typeinfoRefs); } } @@ -759,15 +2029,16 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { }; // create a Pattern of the bytes and the MatchAction to perform upon a match - GenericByteSequencePattern
genericByteMatchPattern = - new GenericByteSequencePattern<>(bytes, action); + GenericByteSequencePattern
genericByteMatchPattern = new GenericByteSequencePattern<>(bytes, action); searcher.addPattern(genericByteMatchPattern); } + /** * Method to determine if the given data is a typeinfo structure + * * @param data the given data * @return true if the given data is a typeinfo structure, else return false */ @@ -794,184 +2065,64 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } /** - * Method to create an appropriate type of vtable (primary, internal, or construction) and - * an associated VTT, if applicable + * Method to create an appropriate type of vtable (primary, internal, or + * construction) and an associated VTT, if applicable + * * @param vtableAddress the given vtable address - * @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 CancelledException, Exception { + private Vtable processVtable(Address vtableAddress, GccTypeinfoRef typeinfoRef, Boolean isConstruction) + throws CancelledException { - // skip the special tables - if (vtableAddress.equals(class_type_info_vtable) || - vtableAddress.equals(si_class_type_info_vtable) || - vtableAddress.equals(vmi_class_type_info_vtable)) { - return; + Vtable vtable = null; + boolean isSpecial = false; + MemoryBlock externalBlock = getExternalBlock(); + boolean isExternal = false; + if (externalBlock != null && externalBlock.contains(vtableAddress)) { + isExternal = true; } - Data dataAt = api.getDataAt(vtableAddress); + if (vtableAddress.equals(class_type_info_vtable) || vtableAddress.equals(si_class_type_info_vtable) + || vtableAddress.equals(vmi_class_type_info_vtable)) { - // first check to see it is an erroneous vtable that has been made a byte array - // if so, clear it and start looking for the typeinfo reference - if (dataAt != null && dataAt.isArray()) { - api.clearListing(vtableAddress); - - } - if (dataAt != null && !dataAt.getDataType().getName().equals("long")) { - api.clearListing(vtableAddress); + isSpecial = true; } - // find the special type info ref - Address typeinfoAddress = findNextTypeinfoRef(vtableAddress); - if (typeinfoAddress == null) { - if (DEBUG) { - Msg.debug(this, vtableNamespace.getName() + - " vtable has no typeinfo ref after vtable at " + vtableAddress.toString()); - } - return; + if (isConstruction == null) { + vtable = new Vtable(program, vtableAddress, typeinfoRef, isSpecial, isExternal, monitor); + } else { + + vtable = new Vtable(program, vtableAddress, typeinfoRef, isSpecial, isExternal, isConstruction, monitor); } - // create the typeinfo pointer if there isn't already one - Data typeinfoPtr = api.getDataAt(typeinfoAddress); - if (typeinfoPtr == null) { - DataType nullPointer = dataTypeManager.getPointer(null); - - api.createData(typeinfoAddress, nullPointer); - + if (isExternal) { + return vtable; } - // if not already named a construction-vtable then check to see if it is one so it can - // be renamed and the new namespace figured out - // know it isn't null because the of the vtable symbol iterator used to call this method in - // the first place - Symbol vtableSymbol = symbolTable.getPrimarySymbol(vtableAddress); - if (!vtableSymbol.getName().equals("construction-vtable") && listOfAllVtables != null) { - // get first VTT before this vtable - Symbol vttSymbolBeforeConstructionVtable = getVTTBefore(vtableSymbol.getAddress()); - if (vttSymbolBeforeConstructionVtable != null) { - List
subVTTs = getSubVTTs(vttSymbolBeforeConstructionVtable.getAddress()); - - if (!subVTTs.isEmpty()) { - int n = 0; - for (Address subVTTAddress : subVTTs) { - monitor.checkCanceled(); - n++; - Symbol constructionVtableSymbol = getNthSymbolOnListAfterAddress( - vttSymbolBeforeConstructionVtable.getAddress(), listOfAllVtables, n); - if (constructionVtableSymbol.equals(vtableSymbol)) { - - // change the namespace and name of the vtable - Namespace classNamespace = createConstructionNamespace(vtableSymbol, - vttSymbolBeforeConstructionVtable); - - 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 " + - vttSymbolBeforeConstructionVtable.getParentNamespace() - .getName(true)); - - } - } - - } - - } - + if (!vtable.isValid()) { + return null; } - // create longs from top of vtable to the typeinfoAddress - createLongs(vtableAddress, typeinfoAddress); - - Address possibleVftableAddress = getAddress(typeinfoAddress, defaultPointerSize); - - if (possibleVftableAddress == null) { - return; - } - - int numFunctionPointers = getNumFunctionPointers(possibleVftableAddress, true, true); - - if (numFunctionPointers == 0) { - // if not a vftable check for an internal vtable - boolean isInternalVtable = - createInternalVtable(possibleVftableAddress, vtableNamespace); - if (isInternalVtable) { - return; - } - // if not an internal vtable check for VTT table - boolean isVTT = createVTT(vtableNamespace, possibleVftableAddress); - if (isVTT) { - return; - } - return; - } - - // if at least one function pointer make vftable label - the createVftable method will - // create the table late - String vftableLabel = VFTABLE_LABEL; - if (!isPrimary) { - vftableLabel = "internal_" + vftableLabel; - } - - symbolTable.createLabel(possibleVftableAddress, vftableLabel, vtableNamespace, - SourceType.ANALYSIS); - - createVftableArray(possibleVftableAddress, numFunctionPointers); - - // check for an internal vtable after the vftable and make a symbol there if there is one - // will process them later - Address possibleInternalVtableAddress = - getAddress(possibleVftableAddress, defaultPointerSize * numFunctionPointers); - // if there is no symbol or a non-default symbol then the nextAddress is an internal - // vtable - if (possibleInternalVtableAddress == null) { - return; - } - - // check to see if it is an internal vtable - boolean isInternalVtable = - createInternalVtable(possibleInternalVtableAddress, vtableNamespace); - if (isInternalVtable) { - return; - } - - // otherwise check to see if it is a VTT table and create it if so - boolean isVTT = createVTT(vtableNamespace, possibleInternalVtableAddress); - if (isVTT) { - return; - } - } - - private Symbol getVTTBefore(Address address) throws CancelledException { - - // get all symbols named VTT and get the one directly before the given address - List vttSymbols = extendedFlatAPI.getListOfSymbolsInAddressSet( - program.getAddressFactory().getAddressSet(), "VTT", true); - - return getSymbolOnListBeforeAddress(address, vttSymbols); + return vtable; } - private List
getSubVTTs(Address vttAddress) { + // TODO: add this back in + private List
getSubVTTs(Address vttAddress) throws CancelledException { - // keep getting next code unit and continue while in the VTT (check for pointers) + // keep getting next code unit and continue while in the VTT (check for + // pointers) // if there is a reference inside the vtt then count it - it is a subVTT int offset = 0; List
subVtts = new ArrayList
(); Address currentAddress = vttAddress; while (currentAddress != null && getPointerToDefinedMemory(currentAddress) != null) { if (offset > 0) { - Reference[] referencesTo = api.getReferencesTo(currentAddress); - if (referencesTo.length > 0) { + + List
referencesTo = getAllReferencesTo(currentAddress); + // Reference[] referencesTo = api.getReferencesTo(currentAddress); + // if (referencesTo.length > 0) { + if (!referencesTo.isEmpty()) { subVtts.add(currentAddress); } } @@ -983,522 +2134,461 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } - /* - * Method to get the address on list that is the first that comes after the given address - */ - private Symbol getSymbolOnListBeforeAddress(Address givenAddress, List listOfSymbols) - throws CancelledException { - - if (listOfSymbols.isEmpty()) { - return null; - } - - Symbol symbolBefore = null; - - listOfSymbols.sort((a1, a2) -> a1.getAddress().compareTo(a2.getAddress())); - - for (Symbol symbol : listOfSymbols) { - monitor.checkCanceled(); - if (symbol.getAddress().getOffset() >= givenAddress.getOffset()) { - return symbolBefore; - } - if (symbolBefore == null) { - symbolBefore = symbol; - continue; - } - if (symbol.getAddress().getOffset() > symbolBefore.getAddress().getOffset()) { - symbolBefore = symbol; - } - - } - return symbolBefore; - } - - private Symbol getNthSymbolOnListAfterAddress(Address givenAddress, List listOfSymbols, - int n) throws CancelledException { - - if (listOfSymbols.isEmpty()) { - return null; - } - - int numSymbolsAfter = 0; - listOfSymbols.sort((a1, a2) -> a1.getAddress().compareTo(a2.getAddress())); - - for (Symbol symbol : listOfSymbols) { - monitor.checkCanceled(); - if (symbol.getAddress().getOffset() > givenAddress.getOffset()) { - - numSymbolsAfter++; - if (numSymbolsAfter == n) { - return symbol; - } - } - } - return null; - } - - private boolean createInternalVtable(Address possibleInternalVtableAddress, - 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); - if (pointer != null) { - return false; - } - - Symbol possibleInternalVtableSymbol = - symbolTable.getPrimarySymbol(possibleInternalVtableAddress); - if (possibleInternalVtableSymbol != null && - possibleInternalVtableSymbol.getSource() != SourceType.DEFAULT && - (!possibleInternalVtableSymbol.getParentNamespace().equals(vtableNamespace) || - !possibleInternalVtableSymbol.getName().contains("vtable"))) { - return false; - } - - if (possibleInternalVtableSymbol == null || - (possibleInternalVtableSymbol.getSource() == SourceType.DEFAULT && - (isValidVtableStart(possibleInternalVtableAddress) || - isValidVftableStart(possibleInternalVtableAddress)))) { - - symbolTable.createLabel(possibleInternalVtableAddress, - "internal_vtable_" + possibleInternalVtableAddress.toString(), vtableNamespace, - SourceType.ANALYSIS); - processVtable(possibleInternalVtableAddress, vtableNamespace, false, null); - return true; - - } - return false; - } - - /** - * Method to create a VTT table label at the given address if it is deemed a valid VTT - * @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) throws Exception { - - // get pointer at address - Address pointer = getPointerToDefinedMemory(address); - if (pointer == null) { - return false; - } - // check if pointer is to the class vftable or to a class internal vtable or to itself - // if not one of those things it isn't a VTT - Symbol symbol = symbolTable.getPrimarySymbol(pointer); - if ((!symbol.getName().equals(VFTABLE_LABEL) || - !symbol.getName().contains("internal_vtable")) && - !symbol.getParentNamespace().equals(classNamespace) && !pointer.equals(address)) { - return false; - } - - // if it is then create the VTT symbol and create pointer there - - symbolTable.createLabel(address, "VTT", classNamespace, SourceType.ANALYSIS); - - DataType nullPointer = dataTypeManager.getPointer(null); - try { - api.createData(pointer, nullPointer); - } - catch (Exception e) { - // already data there so don't try and overwrite it - } - - api.setPlateComment(address, "VTT for " + classNamespace.getName(true)); - - return true; - } - - /** - * Method to check for a valid vtable at the given address - * @param vtableAddress the given address - * @return true if there is a valid vtable at the given address, false otherwise - */ - private boolean isValidVtableStart(Address vtableAddress) { - - // check that no refs into the first 2*defaultptr bytes - // skip top of table since that will have references to it - Address address = getAddress(vtableAddress, 1); - if (address == null) { - return false; - } - if (!areNoReferencesInto(address, 2 * defaultPointerSize - 1)) { - return false; - } - - // check that no pointers - if (!areNoReferencesFrom(vtableAddress, 2 * defaultPointerSize)) { - return false; - } - - // check that no other data exept possibly longs at correct offsets - if (!isNoDataCreatedExceptMaybeLongs(vtableAddress, 2 * defaultPointerSize)) { - return false; - } - - return true; - } - - private boolean areNoReferencesInto(Address topAddress, int length) { - - int offset = 0; - - MemoryBlock currentMemoryBlock = program.getMemory().getBlock(topAddress); - - while (offset < length) { - - Address address = getAddress(topAddress, offset); - - if (address == null) { - return false; - } - - if (!currentMemoryBlock.contains(address)) { - return false; - } - - Reference[] referencesTo = extendedFlatAPI.getReferencesTo(address); - if (referencesTo.length > 0) { - return false; - } - - offset++; - - } - return true; - } - - private boolean areNoReferencesFrom(Address topAddress, int length) { - - int offset = 0; - - MemoryBlock currentMemoryBlock = program.getMemory().getBlock(topAddress); - - while (offset < length) { - - Address address = getAddress(topAddress, offset); - - if (address == null) { - return false; - } - - if (!currentMemoryBlock.contains(address)) { - return false; - } - - List
referenceFromAddresses = - extendedFlatAPI.getReferenceFromAddresses(address); - - if (referenceFromAddresses.size() > 0) { - return false; - } - - offset++; - - } - - return true; - - } - - private boolean isNoDataCreatedExceptMaybeLongs(Address startAddress, int length) { - - int offset = 0; - - MemoryBlock currentMemoryBlock = program.getMemory().getBlock(startAddress); - - while (offset < length) { - - Address address = getAddress(startAddress, offset); - - if (address == null) { - return false; - } - - if (!currentMemoryBlock.contains(address)) { - return false; - } - - Data data = api.getDataAt(address); - - // if there is data and it isn't on a pointer size boundary then return null - // if there is data and it is on a pointer size boundary but isn't a long then - // return null - // otherwise, continue - if (data != null) { - if (offset % defaultPointerSize == 0 && - data.getBaseDataType().getName().equals("long")) { - offset += defaultPointerSize; - continue; - } - return false; - } - offset++; - } - - return true; - - } - - private boolean isValidVftableStart(Address vftableAddress) throws CancelledException { - - // no refs into first defaaultPointerSize bytes - Address address = getAddress(vftableAddress, 1); - if (address == null) { - return false; - } - - if (!areNoReferencesInto(address, defaultPointerSize - 1)) { - return false; - } - - if (extendedFlatAPI.hasNumZeros(vftableAddress, defaultPointerSize)) { - return true; - } - - Data data = api.getDataAt(vftableAddress); - if (data != null) { - if (!data.isPointer()) { - return false; - } - Address referencedAddress = extendedFlatAPI.getSingleReferencedAddress(vftableAddress); - if (referencedAddress == null) { - return false; - } - Function functionAt = api.getFunctionAt(referencedAddress); - if (functionAt != null) { - return true; - } - } - else { - try { - Long longValue = api.getLong(address); - Address functionAddress = address.getNewAddress(longValue); - Function functionAt = api.getFunctionAt(functionAddress); - if (functionAt != null) { - return true; - } - } - catch (MemoryAccessException e) { - return false; - } - catch (AddressOutOfBoundsException e) { - return false; - } - - } - - return false; - } - - /** - * Method to replace the array incorrectly placed at special vftable with longs followed by - * typeinfo label - * @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, InvalidInputException { + public SpecialVtable createSpecialVtable(Address vtableAddress, GccTypeinfo specialTypeinfo) throws Exception { + boolean isExternal = false; + Address typeinfoRefAddress = null; // if vtable is in external block don't try to create it because the full table isn't there - // but is external - if (program.getMemory().isExternalBlockAddress(vtableAddress)) { - return vtableAddress; + // but is partially in placeholder external memory block + if (program.getMemory().getBlock(vtableAddress).getName().equals("EXTERNAL")) { + isExternal = true; } + // if vtable address points to external memory don't try to create because table is + // in external library + Address externalReference = getExternalReference(vtableAddress); + if (externalReference != null) { + isExternal = true; + } + + // if external then there is no typeinfo ref in the vtable - it is in an external program + // if internal then the typeinfo ref for special vtable is the second item in the vtable + if (!isExternal) { + typeinfoRefAddress = vtableAddress.add(defaultPointerSize); + } + + GccTypeinfoRef typeinfoRef = new GccTypeinfoRef(typeinfoRefAddress, specialTypeinfo, true); + Symbol vtableSymbol = symbolTable.getPrimarySymbol(vtableAddress); api.clearListing(vtableAddress); - int vtableLongs = createVtableLongs(vtableAddress); + SpecialVtable specialVtable = new SpecialVtable(program, vtableAddress, typeinfoRef, isExternal, + vtableSymbol.getParentNamespace(), monitor); + return specialVtable; + } - if (vtableLongs > 0) { + public Address getExternalReference(Address address) { - Address typeinfoAddress = vtableAddress.add(vtableLongs * defaultPointerSize); - symbolTable.createLabel(typeinfoAddress, "typeinfo", vtableSymbol.getParentNamespace(), - SourceType.ANALYSIS); - return typeinfoAddress; + Reference[] referencesFrom = program.getReferenceManager().getReferencesFrom(address); + + // get only the address references at the given address (ie no stack refs, ...) + List
refFromAddresses = new ArrayList
(); + for (Reference referenceFrom : referencesFrom) { + if (referenceFrom.isExternalReference()) { + refFromAddresses.add(referenceFrom.getToAddress()); + } } + + if (refFromAddresses.size() == 1) { + return refFromAddresses.get(0); + } + return null; } /** - * Method to create long data type at the given vtable address and return the number created OR - * if they are already created, just return how many there are - * @param vtableAddress the address of the given vtable - * @return the number of long data types at vtableAddress - */ - private int createVtableLongs(Address vtableAddress) { - - AddressSetView programAddressSet = program.getMemory().getAllInitializedAddressSet(); - DataType pointer = dataTypeManager.getPointer(null); - LongDataType longDT = new LongDataType(); - - int offset = 0; - int numLongs = 0; - while (true) { - - Address address = vtableAddress.add(offset); - - // Except for the first one which should have a symbol, if there is a symbol at the - // address, stop making longs because it there are no references into the vtable longs - if (offset > 0 && symbolTable.getPrimarySymbol(address) != null) { - return numLongs; - } - - // create a pointer and check to see if it is a reference to a valid memory location - try { - api.createData(address, pointer); - Address referencedAddress = extendedFlatAPI.getSingleReferencedAddress(address); - - // 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); - api.createData(address, longDT); - offset += defaultPointerSize; - numLongs++; - } - // if it is valid, leave the pointer created and get out of the loop - else { - return numLongs; - } - } - // if bump into existing data return the number found so far - catch (Exception e) { - return numLongs; - } - - } - } - - /** - * Method to create and apply typeinfo structs of one of the three types used by rtti classes + * Method to create and apply typeinfo structs of one of the three types used by + * rtti classes + * * @throws CancelledException if cancelled - * @throws Exception if could not apply a type info structure + * @throws Exception if could not apply a type info structure */ - private List
createTypeinfoStructs() throws CancelledException, Exception { + private List createTypeinfoStructs(List specialTypeinfos, + List specialVtables) throws CancelledException, Exception { StructureDataType classTypeInfoStructure = createClassTypeInfoStructure(); - StructureDataType siClassTypeInfoStructure = - createSiClassTypeInfoStructure(classTypeInfoStructure); - StructureDataType baseClassTypeInfoStructure = - createBaseClassTypeInfoStructure(classTypeInfoStructure); + StructureDataType siClassTypeInfoStructure = createSiClassTypeInfoStructure(classTypeInfoStructure); + StructureDataType baseClassTypeInfoStructure = createBaseClassTypeInfoStructure(classTypeInfoStructure); - List
typeinfoAddresses; + List typeinfos = new ArrayList(specialTypeinfos); - // if dwarf get using symbols - if (isDwarfLoaded) { - typeinfoAddresses = getTypeinfoAddressesUsingSymbols(); - } - else { - // if not, get using ref to specials - if (hasExternalRelocationRefs()) { - typeinfoAddresses = getTypeinfoAddressesUsingRelocationTable(); - } - else { - typeinfoAddresses = getTypeinfoAddressesUsingSpecialTypeinfos(); + // Apply typeinfo structs to special typeinfos if the typeinfo is not in + // external mem block or external program + for (GccTypeinfo specialTypeinfo : specialTypeinfos) { + monitor.checkCancelled(); + + if (specialTypeinfo.isInProgramMemory()) { + applyTypeinfoStructure(siClassTypeInfoStructure, specialTypeinfo.getAddress()); + typeinfoToStructuretypeMap.put(specialTypeinfo.getAddress(), SI_CLASS_TYPE_INFO_STRUCTURE); } } - if (typeinfoAddresses.isEmpty()) { - return typeinfoAddresses; + AddressSetView executeSet = program.getMemory().getExecuteSet(); + MemoryBlock idataBlock = program.getMemory().getBlock(".idata"); + + AddressSet specialTypeinfosAddrSet = getSpecialTypeinfosAddrSet(); + + for (SpecialVtable specialVtable : specialVtables) { + + monitor.checkCancelled(); + + Address typeinfoRefAddr = specialVtable.getVfunctionTop(); + if (typeinfoRefAddr == null) { + typeinfoRefAddr = specialVtable.getAddress(); + } + + List
refsToClassTypeinfo = getAllReferencesTo(typeinfoRefAddr); + for (Address typeinfoAddress : refsToClassTypeinfo) { + + monitor.checkCancelled(); + + if (executeSet.contains(typeinfoAddress)) { + continue; + } + + // check to see if the reference is in a special vtable or special typeinfo and + // skip if so only looking to return the non-special typeinfos + if (specialTypeinfosAddrSet.contains(typeinfoAddress)) { + continue; + } + + if (hasExistingTypeinfoStructure(typeinfoAddress)) { + continue; + } + + // skip if ref is in idata (windows gcc IAT) + if (idataBlock != null && idataBlock.contains(typeinfoAddress)) { + continue; + } + + // test if creating the pointer at typeinfoAddress would overlap anything + // else and skip if so + if (!canContainPointer(typeinfoAddress)) { + continue; + } + + Data newStructure = null; + String specialTypeinfoNamespaceName = null; + + // create a "no inheritance" struct here + if (specialVtable.getNamespace().getName().equals(CLASS_TYPEINFO_NAMESPACE)) { + specialTypeinfoNamespaceName = CLASS_TYPEINFO_NAMESPACE; + typeinfoToStructuretypeMap.put(typeinfoAddress, CLASS_TYPE_INFO_STRUCTURE); + newStructure = applyTypeinfoStructure(classTypeInfoStructure, typeinfoAddress); + } + + // create a "single inheritance" struct here + else if (specialVtable.getNamespace().getName().equals(SI_CLASS_TYPEINFO_NAMESPACE)) { + specialTypeinfoNamespaceName = SI_CLASS_TYPEINFO_NAMESPACE; + typeinfoToStructuretypeMap.put(typeinfoAddress, SI_CLASS_TYPE_INFO_STRUCTURE); + newStructure = applyTypeinfoStructure(siClassTypeInfoStructure, typeinfoAddress); + } + + // create a "virtual multip inheritance" struct here + else if (specialVtable.getNamespace().getName().equals(VMI_CLASS_TYPEINFO_NAMESPACE)) { + specialTypeinfoNamespaceName = VMI_CLASS_TYPEINFO_NAMESPACE; + typeinfoToStructuretypeMap.put(typeinfoAddress, VMI_CLASS_TYPE_INFO_STRUCTURE); + Structure vmiClassTypeinfoStructure = getOrCreateVmiTypeinfoStructure(typeinfoAddress, + baseClassTypeInfoStructure); + if (vmiClassTypeinfoStructure != null) { + newStructure = applyTypeinfoStructure(vmiClassTypeinfoStructure, typeinfoAddress); + } + } + + if (newStructure == null) { + // is a typeinfo that inherits a non class typeinfo so skip it + continue; + } + + // check for existing symbol and if none, demangle the name and apply + Symbol typeinfoSymbol = api.getSymbolAt(typeinfoAddress); + if (typeinfoSymbol == null || typeinfoSymbol.getSource() == SourceType.DEFAULT + || typeinfoSymbol.getName().startsWith(".rdata$")) { + + typeinfoSymbol = createDemangledTypeinfoSymbol(typeinfoAddress); + if (typeinfoSymbol == null) { + Msg.debug(this, "Could not create demangled typeinfo symbol at " + typeinfoAddress.toString()); + continue; + } + } + + if (typeinfoSymbol != null && typeinfoSymbol.getName().equals("typeinfo")) { + promoteToClassNamespace(typeinfoSymbol.getParentNamespace()); + GccTypeinfo typeinfo = createGccTypeinfo(typeinfoSymbol, false); + if (specialTypeinfoNamespaceName == null) { + continue; + } + GccTypeinfo specialTypeinfo = getTypeinfo(specialTypeinfoNamespaceName, specialTypeinfos); + typeinfo.setInheritedSpecialTypeinfo(specialTypeinfo); + typeinfos.add(typeinfo); + continue; + } + } } - List
typeinfoAddressesToProcess = new ArrayList
(); - - for (Address typeinfoAddress : typeinfoAddresses) { - - monitor.checkCanceled(); - - if (hasExistingTypeinfoStructure(typeinfoAddress)) { + // remove typeinfos that do not inherit one of the three special typeinfos + List typeinfosToRemove = new ArrayList(); + Map typeinfoMap = new HashMap(); + + for (GccTypeinfo typeinfo : typeinfos) { + monitor.checkCancelled(); + Address typeinfoAddress = typeinfo.getAddress(); + if (typeinfo.getInheritedSpecialTypeinfo() == null) { + + typeinfosToRemove.add(typeinfo); continue; } - - Address specialTypeinfoRef = - extendedFlatAPI.getSingleReferencedAddress(typeinfoAddress); - if (specialTypeinfoRef == null) { + typeinfoMap.put(typeinfoAddress, typeinfo); + } + typeinfos.removeAll(typeinfosToRemove); + + // update typeinfos with their base classes + updateTypeinfosWithBases(typeinfos, typeinfoMap); + + return typeinfos; + } + + private GccTypeinfo getTypeinfo(String namespaceName, List typeinfos) throws CancelledException { + + for (GccTypeinfo typeinfo : typeinfos) { + monitor.checkCancelled(); + + if (typeinfo.getNamespace().getName().equals(namespaceName)) { + return typeinfo; + } + } + return null; + + } + + private void updateTypeinfosWithBases(List typeinfos, Map typeinfoMap) + throws CancelledException { + + List invalidTypeinfos = new ArrayList(); + for (GccTypeinfo typeinfo : typeinfos) { + monitor.checkCancelled(); + + if (typeinfo.isSpecialTypeinfo) { continue; } - if (!isSpecialTypeinfo(specialTypeinfoRef)) { - // check for EXTERNAL block and look for specialTypeinfoRef there - // if fix works, put external block error message and to contact us - if (!hasExternalBlock()) { - continue; - } - // use referenced vtable symbol name instead since when in EXTERNAL block - // since can't get at the typeinfo ref in that block - if (!isSpecialVtable(specialTypeinfoRef)) { - continue; - } - } - - Data newStructure = null; - - // create a "no inheritance" struct here - if (specialTypeinfoRef.equals(class_type_info) || - specialTypeinfoRef.equals(class_type_info_vtable)) { - - newStructure = applyTypeinfoStructure(classTypeInfoStructure, typeinfoAddress); - } - - // create a "single inheritance" struct here - else if (specialTypeinfoRef.equals(si_class_type_info) || - specialTypeinfoRef.equals(si_class_type_info_vtable)) { - - newStructure = applyTypeinfoStructure(siClassTypeInfoStructure, typeinfoAddress); - } - - // create a "virtual multip inheritance" struct here - else if (specialTypeinfoRef.equals(vmi_class_type_info) || - specialTypeinfoRef.equals(vmi_class_type_info_vtable)) { - - Structure vmiClassTypeinfoStructure = - getOrCreateVmiTypeinfoStructure(typeinfoAddress, baseClassTypeInfoStructure); - if (vmiClassTypeinfoStructure != null) { - newStructure = - applyTypeinfoStructure(vmiClassTypeinfoStructure, typeinfoAddress); - } - } - - if (newStructure == null) { - throw new Exception( - "ERROR: Could not apply typeinfo structure to " + typeinfoAddress); - } - - typeinfoAddressesToProcess.add(typeinfoAddress); - - // check for existing symbol and if none, demangle the name and apply - Symbol typeinfoSymbol = api.getSymbolAt(typeinfoAddress); - if (typeinfoSymbol == null || typeinfoSymbol.getSource() == SourceType.DEFAULT) { - typeinfoSymbol = createDemangledTypeinfoSymbol(typeinfoAddress); - if (typeinfoSymbol == null) { - Msg.debug(this, "Could not create demangled typeinfo symbol at " + - typeinfoAddress.toString()); - } - } - - if (typeinfoSymbol != null && typeinfoSymbol.getName().equals("typeinfo")) { - promoteToClassNamespace(typeinfoSymbol.getParentNamespace()); + // can't process if in external block + if (inExternalBlock(typeinfo.getAddress())) { + invalidTypeinfos.add(typeinfo); continue; } + // TODO: update the typeinfo with the correct namespace based on the structure + + String namespaceName = typeinfo.getInheritedSpecialTypeinfo().getNamespace().getName(); + + // if typeinfo inherits class_type_info then no Base to update + if (namespaceName.equals(CLASS_TYPEINFO_NAMESPACE)) { + continue; + } + + if (namespaceName.equals(SI_CLASS_TYPEINFO_NAMESPACE)) { + if (!updateSiTypeinfo(typeinfo, typeinfoMap)) { + invalidTypeinfos.add(typeinfo); + } + continue; + } + + if (namespaceName.equals(VMI_CLASS_TYPEINFO_NAMESPACE)) { + if (!updateVmiTypeinfo(typeinfo, typeinfoMap)) { + invalidTypeinfos.add(typeinfo); + } + } + } + typeinfos.removeAll(invalidTypeinfos); + + } + + private boolean updateSiTypeinfo(GccTypeinfo typeinfo, Map typeinfoMap) + throws CancelledException { + + Data siTypeinfoStructure = api.getDataAt(typeinfo.getAddress()); + + // SI_CLASS_TYPE_INFO_STRUCTURE + if (siTypeinfoStructure == null || !siTypeinfoStructure.isStructure()) { + throw new IllegalArgumentException( + siTypeinfoStructure.getAddressString(false, false) + " is not a structure"); + } + + Data baseClassPointer = siTypeinfoStructure.getComponent(2); + + Address baseClassPointerAddress = baseClassPointer.getAddress(); + Address baseTypeinfoAddress = extendedFlatAPI.getReferencedAddress(baseClassPointerAddress, false); + + if (baseTypeinfoAddress == null) { + Msg.debug(this, typeinfo.getAddress() + ": invalid typeinfo - cannot get address for baseTypeinfo"); + return false; + } + + GccTypeinfo baseTypeinfo = typeinfoMap.get(baseTypeinfoAddress); + if(baseTypeinfo == null) { + return false; + } + + // si_class_type_info by definition have single base that is public, not + // virtual, and is at offset 0 + typeinfo.addBaseTypeinfo(baseTypeinfo, 0, true, false, 0); + return true; + } + + private boolean updateVmiTypeinfo(GccTypeinfo typeinfo, Map typeinfoMap) + throws CancelledException { + + Data vmiTypeinfoStructure = api.getDataAt(typeinfo.getAddress()); + + // VMI_CLASS_TYPE_INFO_STRUCTURE + if (vmiTypeinfoStructure == null || !vmiTypeinfoStructure.isStructure()) { + throw new IllegalArgumentException( + vmiTypeinfoStructure.getAddressString(false, false) + " is not a structure"); + } + + long inheritanceFlagValue = getVmiInheritanceFlag(vmiTypeinfoStructure); + typeinfo.addInheritanceFlagValue(inheritanceFlagValue); + + int numBaseClasses = getVmiNumBaseClasses(vmiTypeinfoStructure); + + Data baseClassArray = vmiTypeinfoStructure.getComponent(4); + + for (int i = 0; i < numBaseClasses; i++) { + monitor.checkCancelled(); + + Data baseClassStructure = baseClassArray.getComponent(i); + Address baseClassStructureAddress = baseClassStructure.getAddress(); + Address baseTypeinfoAddress = extendedFlatAPI.getReferencedAddress(baseClassStructureAddress, false); + + if (baseTypeinfoAddress == null) { + Msg.debug(this, + typeinfo.getAddress() + ": invalid typeinfo - cannot get address at baseTypeinfo[" + i + "]"); + return false; + } + + GccTypeinfo baseTypeinfo = typeinfoMap.get(baseTypeinfoAddress); + + if (baseTypeinfo == null) { + Msg.debug(this, typeinfo.getAddress() + + ": invalid typeinfo - no special classtypeinfo ref'd by baseTypeinfo[" + i + "]"); + return false; + } + + // get public/virtual/offset flag + Address flagAddress = baseClassStructureAddress.add(defaultPointerSize); + long publicVirtualOffsetFlag = extendedFlatAPI.getLongValueAt(flagAddress); + + // The low-order byte of __offset_flags contains flags, as given by the masks + // from the enumeration __offset_flags_masks: + + // 0x1: Base class is virtual + // 0x2: Base class is public + + boolean isVirtual = false; + boolean isPublic = false; + + long virtualMask = 0x1L; + long publicMask = 0x2L; + long offsetMask; + if (defaultPointerSize == 4) { + offsetMask = 0xffffff00L; + + } else { + offsetMask = 0xffffffffffffff00L; + } + + if ((publicVirtualOffsetFlag & virtualMask) == 1) { + isVirtual = true; + } + + if (((publicVirtualOffsetFlag & publicMask) >> 1) == 1) { + isPublic = true; + } + + long offset = (publicVirtualOffsetFlag & offsetMask) >> 8; + + typeinfo.addBaseTypeinfo(baseTypeinfo, i, isPublic, isVirtual, offset); + } - return typeinfoAddressesToProcess; + return true; + } - + + private long getVmiInheritanceFlag(Data vmiTypeinfoStructure) { + + // TODO: make a validate structure method and pass name + if (vmiTypeinfoStructure == null || !vmiTypeinfoStructure.isStructure()) { + throw new IllegalArgumentException( + vmiTypeinfoStructure.getAddressString(false, false) + " is not a structure"); + } + + Data inheritanceFlagComponent = vmiTypeinfoStructure.getComponent(2); + Address flagAddress = inheritanceFlagComponent.getAddress(); + DataType inheritanceFlagDataType = inheritanceFlagComponent.getDataType(); + MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), flagAddress); + Scalar scalar = (Scalar) inheritanceFlagDataType.getValue(buf, inheritanceFlagDataType.getDefaultSettings(), + inheritanceFlagDataType.getLength()); + long inheritanceFlagValue = scalar.getUnsignedValue(); + return inheritanceFlagValue; + } + + private int getVmiNumBaseClasses(Data vmiTypeinfoStructure) { + + // TODO: make a validate structure method and pass name + if (vmiTypeinfoStructure == null || !vmiTypeinfoStructure.isStructure()) { + throw new IllegalArgumentException( + vmiTypeinfoStructure.getAddressString(false, false) + " is not a structure"); + } + + Data numBaseClassesComponent = vmiTypeinfoStructure.getComponent(3); + Address numBaseClassesAddress = numBaseClassesComponent.getAddress(); + DataType numBaseClassesDataType = numBaseClassesComponent.getDataType(); + MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), numBaseClassesAddress); + Scalar scalar = (Scalar) numBaseClassesDataType.getValue(buf, numBaseClassesDataType.getDefaultSettings(), + numBaseClassesDataType.getLength()); + int numBaseClasses = (int) scalar.getUnsignedValue(); + + return numBaseClasses; + } + /** - * Method to determine if the given address has one of the ClassTypeinfoDataType types applied + * Method to determine whether a pointer can validly exist at this location + * + * @param pointer + * @return true if a pointer can exist here, false if something exists that + * would not indicate a valid ptr would be here + * @throws CancelledException + */ + private boolean canContainPointer(Address pointer) throws CancelledException { + + // return true if has a correcly sized ptr already - + Data data = program.getListing().getDataAt(pointer); + if (data != null && data.isPointer()) { + return true; + } + + // ok if has symbol at the actual addr so don't check it + int offset = 1; + + while (offset < defaultPointerSize) { + monitor.checkCancelled(); + Address addr = pointer.add(offset); + data = program.getListing().getDataContaining(addr); + if (data != null) { + return false; + } + + Symbol[] symbols = symbolTable.getSymbols(addr); + if (symbols.length != 0) { + return false; + } + } + + return true; + + } + + /** + * Method to determine if the given address has one of the ClassTypeinfoDataType + * types applied + * * @param address the given address * @return true if already has a class data type applied or false if not */ private boolean hasExistingTypeinfoStructure(Address address) { - Data dataAt = api.getDataAt(address); if (dataAt == null) { @@ -1511,7 +2601,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { return false; } - // This has to be "contains" to get all types of class structures some begin and end + // This has to be "contains" to get all types of class structures some begin and + // end // with other things if (!dataType.getName().contains(CLASS_TYPE_INFO_STRUCTURE)) { return false; @@ -1528,15 +2619,13 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { throws CancelledException, AddressOutOfBoundsException, Exception { api.clearListing(typeinfoAddress, typeinfoAddress.add(typeInfoStructure.getLength() - 1)); - Data newStructure; - - newStructure = api.createData(typeinfoAddress, typeInfoStructure); + Data newStructure = api.createData(typeinfoAddress, typeInfoStructure); return newStructure; } private Structure getOrCreateVmiTypeinfoStructure(Address typeinfoAddress, - StructureDataType baseClassTypeInfoStructure) { + StructureDataType baseClassTypeInfoStructure) throws CancelledException { // get num base classes int offsetOfNumBases = 2 * defaultPointerSize + 4; @@ -1549,105 +2638,105 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { return null; } + Msg.debug(this, "numBases for typeinfo: " + typeinfoAddress.toString() + " at address " + + typeinfoAddress.add(offsetOfNumBases) + " numbases: " + numBases); + ; + // 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); + vmiClassTypeinfoStructure = createVmiClassTypeInfoStructure(baseClassTypeInfoStructure, numBases); } return vmiClassTypeinfoStructure; } private Symbol createDemangledTypeinfoSymbol(Address typeinfoAddress) - throws DuplicateNameException, InvalidInputException { + throws DuplicateNameException, InvalidInputException, CancelledException { - String mangledTypeinfo = getTypeinfoName(typeinfoAddress); - if (mangledTypeinfo == null) { + // TODO: 1. see if there is a mangled name that didn't get demangled at + // TODO: 2 - refactor the three places that call this to just call getSymbolAt and + // in that method check for regular symbol and return or check for mangled + // symbol that didn't get demangled then return or + // check for this scenario where you need to get the string out + + Address typeinfoNameAddress = getTypeinfoNameAddress(typeinfoAddress); + + if (typeinfoNameAddress == null) { + return null; + } + + String mangledTypeinfoString = getStringAtAddress(typeinfoNameAddress); + + if (mangledTypeinfoString == null) { Msg.debug(this, "Could not get typeinfo string from " + typeinfoAddress.toString()); return null; } - if (mangledTypeinfo.startsWith("*")) { - mangledTypeinfo = mangledTypeinfo.substring(1); - } - mangledTypeinfo = "_Z" + mangledTypeinfo; - - DemanglerOptions options = new DemanglerOptions(); - options.setDemangleOnlyKnownPatterns(false); - options.setApplySignature(false); - options.setDoDisassembly(false); - - DemangledObject demangled = DemanglerUtil.demangle(mangledTypeinfo); - if (demangled == null) { - Msg.debug(this, "Could not demangle typeinfo string at " + typeinfoAddress.toString()); - return null; + if (mangledTypeinfoString.startsWith("*")) { + mangledTypeinfoString = mangledTypeinfoString.substring(1); } - String namespaceString = demangled.getNamespaceString(); + if (mangledTypeinfoString.startsWith(".rdata$")) { + mangledTypeinfoString = mangledTypeinfoString.substring(7); + } + mangledTypeinfoString = "_ZTS" + mangledTypeinfoString; - Namespace classNamespace = createTypeinfoClassNamespace(namespaceString); + symbolTable.createLabel(typeinfoNameAddress, mangledTypeinfoString, globalNamespace, SourceType.ANALYSIS); - Msg.debug(this, typeinfoAddress.toString() + " " + namespaceString); + // demangle the symbol + DemanglerCmd cmd = new DemanglerCmd(typeinfoNameAddress, mangledTypeinfoString); + cmd.applyTo(program, monitor); - if (classNamespace == null) { + // get the newly created symbol to get the namespace + Symbol typeinfoNameSymbol = symbolTable.getPrimarySymbol(typeinfoNameAddress); + + // TODO: need to account for rare case where there are more than one typeinfos with + // exact same class and name so make two classes in this case - name second one dupe# + // TODO: instead/also - eliminate the ones with no refs or just pick one? + List symbols = symbolTable.getSymbols(typeinfoNameSymbol.getName(), + typeinfoNameSymbol.getParentNamespace()); + if (symbols.size() > 1) { + + Msg.debug(this, "Duplicate typeinfo namespace: " + typeinfoNameSymbol.getParentNamespace().toString()); + for (Symbol symbol : symbols) { + Msg.debug(this, symbol.getAddress()); + } + Namespace newNamespace = symbolTable.getOrCreateNameSpace(globalNamespace, + typeinfoNameSymbol.getParentNamespace().getName(true) + "DUPE", SourceType.ANALYSIS); + try { + typeinfoNameSymbol.setNamespace(newNamespace); + } catch (DuplicateNameException e) { + return null; + } catch (InvalidInputException e) { + return null; + } catch (CircularDependencyException e) { + return null; + } + + } + + Namespace classNamespace = typeinfoNameSymbol.getParentNamespace(); + + Msg.debug(this, typeinfoAddress.toString() + " " + classNamespace.getName()); + + if (classNamespace.isGlobal()) { Msg.debug(this, - typeinfoAddress.toString() + - "Could not create a class namespace for demangled namespace string " + - namespaceString); + typeinfoAddress.toString() + "Could not create a class namespace for demangled namespace string "); return null; } // create the new typeinfo symbol in the demangled namespace + Symbol newSymbol = symbolTable.createLabel(typeinfoAddress, "typeinfo", classNamespace, SourceType.ANALYSIS); + + api.setPlateComment(typeinfoAddress, "typeinfo for " + classNamespace.getName(true)); - Symbol newSymbol = symbolTable.createLabel(typeinfoAddress, "typeinfo", classNamespace, - SourceType.ANALYSIS); return newSymbol; } - private Namespace createTypeinfoClassNamespace(String namespaceString) - throws DuplicateNameException, InvalidInputException { + private Address getTypeinfoNameAddress(Address typeinfoAddress) { - int indexOfColons = namespaceString.indexOf("::"); - Namespace namespace = globalNamespace; - while (indexOfColons != -1) { - String namespaceName = namespaceString.substring(0, indexOfColons); - Namespace newNamespace = getOrCreateNamespace(namespaceName, namespace); - if (newNamespace == null) { - return null; - } - namespace = newNamespace; - namespaceString = namespaceString.substring(indexOfColons + 2); - indexOfColons = namespaceString.indexOf("::"); - } - // the substring after the last :: is the class namespace we want to return - Namespace classNamespace = getOrCreateNamespace(namespaceString, namespace); - if (classNamespace == null) { - return null; - } - - if (classNamespace.getSymbol().getSymbolType() != SymbolType.CLASS) { - classNamespace = promoteToClassNamespace(classNamespace); - } - - return classNamespace; - } - - private Namespace getOrCreateNamespace(String namespaceName, Namespace parentNamespace) - throws DuplicateNameException, InvalidInputException { - - Namespace namespace = symbolTable.getNamespace(namespaceName, parentNamespace); - if (namespace == null) { - - namespace = - symbolTable.createNameSpace(parentNamespace, namespaceName, SourceType.ANALYSIS); - } - return namespace; - } - - private String getTypeinfoName(Address address) { - - Data dataAt = api.getDataAt(address); + Data dataAt = api.getDataAt(typeinfoAddress); if (dataAt == null) { return null; } @@ -1665,15 +2754,38 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { return null; } - Address stringReference = extendedFlatAPI - .getSingleReferencedAddress(address.add(typeinfoNameComponent.getOffset())); + Address typeinfoNameAddress = extendedFlatAPI + .getSingleReferencedAddress(typeinfoAddress.add(typeinfoNameComponent.getOffset())); - Data stringData = api.getDataAt(stringReference); + return typeinfoNameAddress; + } + + String getStringAtAddress(Address address) throws CancelledException { + + Data stringData = api.getDataAt(address); if (stringData == null) { - return null; + + // account for randomly occurring bad strings sucking up the real expected + // string + Data dataContaining = api.getDataContaining(address); + if (dataContaining != null) { + api.clearListing(dataContaining.getAddress()); + } + // create string + try { + stringData = api.createAsciiString(address); + } catch (Exception e) { + Msg.debug(this, "Could not create string at " + address); + return null; + } + + if (stringData == null) { + return null; + } + } int stringLen = stringData.getLength(); - MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), stringReference); + MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), address); StringDataType sdt = new StringDataType(); @@ -1684,174 +2796,103 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { return str; } - /** - * Method to get a list typeinfo addresses using symbols - * @return a list of non-special typeinfo addresses that have "typeinfo" symbols - * @throws CancelledException if cancelled - */ - private List
getTypeinfoAddressesUsingSymbols() throws CancelledException { - - List
typeinfoAddresses = new ArrayList
(); - - AddressSet nonExecutableAddressSet = program.getAddressFactory() - .getAddressSet() - .subtract(program.getMemory().getExecuteSet()); - - List typeinfoSymbols = - extendedFlatAPI.getListOfSymbolsInAddressSet(nonExecutableAddressSet, "typeinfo", true); - - Iterator typeinfoIterator = typeinfoSymbols.iterator(); - while (typeinfoIterator.hasNext()) { - - monitor.checkCanceled(); - - Symbol typeinfoSymbol = typeinfoIterator.next(); - Address typeinfoAddress = typeinfoSymbol.getAddress(); - - // skip the typeinfo symbols from the three special typeinfos - if (isSpecialTypeinfo(typeinfoAddress)) { - continue; - } - // check for EXTERNAL block and look for specialTypeinfoRef there - // if fix works, put external block error message and to contact us - if (hasExternalBlock() && isSpecialVtable(typeinfoAddress)) { - continue; - } - - typeinfoAddresses.add(typeinfoAddress); - } - return typeinfoAddresses; - } - - /** - * Method to get a list typeinfo addresses using relocation table info - * @return a list of typeinfo addresses - * @throws CancelledException if cancelled - */ - private List
getTypeinfoAddressesUsingRelocationTable() throws CancelledException { - - List
typeinfoAddresses = new ArrayList
(); - - AddressSetView executeSet = program.getMemory().getExecuteSet(); - - Iterator bookmarksIterator = - program.getBookmarkManager().getBookmarksIterator(BookmarkType.ERROR); - while (bookmarksIterator.hasNext()) { - monitor.checkCanceled(); - Bookmark bookmark = bookmarksIterator.next(); - Address bookmarkAddress = bookmark.getAddress(); - if (bookmark.getCategory().equals("EXTERNAL Relocation") && - bookmarkContainsSpecialTypeinfoName(bookmark.getComment()) && - !executeSet.contains(bookmarkAddress)) { - typeinfoAddresses.add(bookmarkAddress); - } - } - return typeinfoAddresses; - } - - private boolean bookmarkContainsSpecialTypeinfoName(String bookmarkComment) { - - if (bookmarkComment.contains("class_type_info")) { - return true; - } - - if (bookmarkComment.contains("si_class_type_info")) { - return true; - } - if (bookmarkComment.contains("vmi_class_type_info")) { - return true; - } - return false; - } /** * Method to check to see if there are any EXTERNAL block relocations - * @return true if there are any EXTERNAL block relocations in the program, false otherwise + * + * @return true if there are any EXTERNAL block relocations in the program, + * false otherwise * @throws CancelledException if cancelled */ - private boolean hasExternalRelocationRefs() throws CancelledException { - // if no external block then there won't be any refernces to special typeinfos in external + private boolean hasExternalRelocations() throws CancelledException { + // if no external block then there won't be any refernces to special typeinfo in external // block so return empty list if (!hasExternalBlock()) { return false; } - Iterator bookmarksIterator = - program.getBookmarkManager().getBookmarksIterator(BookmarkType.ERROR); + Iterator bookmarksIterator = program.getBookmarkManager().getBookmarksIterator(BookmarkType.WARNING); while (bookmarksIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Bookmark bookmark = bookmarksIterator.next(); - if (bookmark.getCategory().equals("EXTERNAL Relocation")) { + if (bookmark.getCategory().startsWith("EXTERNAL Relocation")) { return true; } } 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 { + // TODO: update to not use global vars + private AddressSet getSpecialTypeinfosAddrSet() { - AddressSetView executeSet = program.getMemory().getExecuteSet(); - List
specialTypeinfoRefs = new ArrayList
(); + AddressSet addrSet = new AddressSet(); + + Integer vtableSize = vtableToSizeMap.get(class_type_info_vtable); + if (vtableSize != null) { + addrSet.add(class_type_info_vtable, class_type_info_vtable.add(vtableSize)); + } + + vtableSize = vtableToSizeMap.get(si_class_type_info_vtable); + if (vtableSize != null) { + addrSet.add(si_class_type_info_vtable, si_class_type_info_vtable.add(vtableSize)); + } + + vtableSize = vtableToSizeMap.get(vmi_class_type_info_vtable); + if (vtableSize != null) { + addrSet.add(vmi_class_type_info_vtable, vmi_class_type_info_vtable.add(vtableSize)); + } if (class_type_info != null) { - Reference[] refsToClassTypeinfo = api.getReferencesTo(class_type_info); - for (Reference ref : refsToClassTypeinfo) { - monitor.checkCanceled(); - Address typeinfoAddress = ref.getFromAddress(); - if (executeSet.contains(typeinfoAddress)) { - continue; - } - specialTypeinfoRefs.add(typeinfoAddress); + Data data = extendedFlatAPI.getDataContaining(class_type_info); + if (data != null && data.getDataType().getName().contains(SI_CLASS_TYPE_INFO_STRUCTURE)) { + addrSet.add(data.getAddress(), data.getAddress().add(data.getLength())); } } if (si_class_type_info != null) { - Reference[] refsToSiClassTypeinfo = api.getReferencesTo(si_class_type_info); - for (Reference ref : refsToSiClassTypeinfo) { - monitor.checkCanceled(); - Address typeinfoAddress = ref.getFromAddress(); - if (executeSet.contains(typeinfoAddress)) { - continue; - } - specialTypeinfoRefs.add(typeinfoAddress); + Data data = extendedFlatAPI.getDataContaining(si_class_type_info); + if (data != null && data.getAddress() == null) { + Msg.debug(this, "si_class_type_info at " + si_class_type_info.toString() + " has null addr"); + } + if (data != null && data.getDataType().getName().contains(SI_CLASS_TYPE_INFO_STRUCTURE)) { + addrSet.add(data.getAddress(), data.getAddress().add(data.getLength())); } } if (vmi_class_type_info != null) { - Reference[] refsToVmiClassTypeinfo = api.getReferencesTo(vmi_class_type_info); - for (Reference ref : refsToVmiClassTypeinfo) { - monitor.checkCanceled(); - Address typeinfoAddress = ref.getFromAddress(); - if (executeSet.contains(typeinfoAddress)) { - continue; - } - specialTypeinfoRefs.add(typeinfoAddress); + Data data = extendedFlatAPI.getDataContaining(vmi_class_type_info); + if (data != null && data.getDataType().getName().contains(SI_CLASS_TYPE_INFO_STRUCTURE)) { + addrSet.add(data.getAddress(), data.getAddress().add(data.getLength())); } } - return specialTypeinfoRefs; + return addrSet; + } /** - * Method to call the various methods to determine whether the functions that make references to - * the vftables are constructors, destructors, deleting destructors, clones, or vbase functions - * @throws CancelledException if cancelled - * @throws InvalidInputException if issues setting function return - * @throws DuplicateNameException if try to create same symbol name already in namespace + * Method to call the various methods to determine whether the functions that + * make references to the vftables are constructors, destructors, deleting + * destructors, clones, or vbase functions + * + * @throws CancelledException if cancelled + * @throws InvalidInputException if issues setting function return + * @throws DuplicateNameException if try to create same symbol name already in + * namespace * @Exception if issues making labels */ private void processConstructorAndDestructors() throws CancelledException, InvalidInputException, DuplicateNameException, Exception { + assignConstructorsAndDestructorsUsingExistingNameNew(recoveredClasses); + + // find gcc destructors in top of vftables + findVftableDestructors(recoveredClasses); + // figure out which are inlined and put on separate list to be processed later separateInlinedConstructorDestructors(recoveredClasses); // figure out which member functions are constructors and which are destructors - // using the order their parents are called + // using the order their parents are called processRegularConstructorsAndDestructorsUsingCallOrder(recoveredClasses); // determine which of the inlines are constructors and which are destructors @@ -1861,44 +2902,189 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { findInlineConstructorsAndDestructorsUsingRelatedClassFunctions(recoveredClasses); - // use the load/store information from decompiler to figure out as many of the + // use the load/store information from decompiler to figure out as many of the // ones that could not be determined in earlier stages processRemainingIndeterminateConstructorsAndDestructors(recoveredClasses); - // use the known constructors and known vfunctions to figure out + // use the known constructors and known vfunctions to figure out // clone functions - // findCloneFunctions(recoveredClasses); + // findCloneFunctions(recoveredClasses); - // This has to be here. It needs all the info from the previously run methods to do this. - // Finds the constructors that have multiple basic blocks, reference the vftable not in the - // first block, and call non-parent constructors and non operator new before the vftable ref - // findMoreInlinedConstructors(recoveredClasses); + // This has to be here. It needs all the info from the previously run methods to + // do this. + // Finds the constructors that have multiple basic blocks, reference the vftable + // not in the + // first block, and call non-parent constructors and non operator new before the + // vftable ref + // findMoreInlinedConstructors(recoveredClasses); - // findDestructorsWithNoParamsOrReturn(recoveredClasses); + // findDestructorsWithNoParamsOrReturn(recoveredClasses); - // use vftables with references to all the same function (except possibly one deleting + // use vftables with references to all the same function (except possibly one + // deleting // destructor)to find the purecall function - // identifyPureVirtualFunction(recoveredClasses); + // identifyPureVirtualFunction(recoveredClasses); - // findRealVBaseFunctions(recoveredClasses); + // findRealVBaseFunctions(recoveredClasses); // make constructors and destructors this calls makeConstructorsAndDestructorsThiscalls(recoveredClasses); } - private StructureDataType createClassTypeInfoStructure() { + public void assignConstructorsAndDestructorsUsingExistingNameNew(List recoveredClasses) + throws CancelledException, InvalidInputException, DuplicateNameException, CircularDependencyException { + + Iterator recoveredClassIterator = recoveredClasses.iterator(); + while (recoveredClassIterator.hasNext()) { + monitor.checkCancelled(); + RecoveredClass recoveredClass = recoveredClassIterator.next(); + + Namespace classNamespace = recoveredClass.getClassNamespace(); + String name = classNamespace.getName(); + SymbolIterator classSymbols = symbolTable.getSymbols(classNamespace); + + while (classSymbols.hasNext()) { + monitor.checkCancelled(); + + Symbol classSymbol = classSymbols.next(); + + Function function = api.getFunctionAt(classSymbol.getAddress()); + if (function == null) { + continue; + } + + if (classSymbol.getName().equals(name)) { + + addConstructorToClass(recoveredClass, function); + removeFromIndeterminateLists(recoveredClasses, function); + continue; + } + if (classSymbol.getName().equals("~" + name)) { + addDestructorToClass(recoveredClass, function); + removeFromIndeterminateLists(recoveredClasses, function); + continue; + } + } + + } + } + + private void findVftableDestructors(List recoveredClasses) throws CancelledException { + + for (RecoveredClass recoveredClass : recoveredClasses) { + + monitor.checkCancelled(); + + List
vftableAddresses = recoveredClass.getVftableAddresses(); + + for (Address vftableAddress : vftableAddresses) { + monitor.checkCancelled(); + + List virtualFunctions = recoveredClass.getVirtualFunctions(vftableAddress); + + if (virtualFunctions.size() < 2) { + continue; + } + + Function firstVfunction = virtualFunctions.get(0); + Function secondVfunction = virtualFunctions.get(1); + + Address callingAddressOfFirstVfunction = getCallingAddress(secondVfunction, firstVfunction); + if (callingAddressOfFirstVfunction == null) { + continue; + } + + // TODO: eventually work into new op delete discovery + Address callingAddrOfOpDelete = getCallingAddress(secondVfunction, "operator.delete"); + if (callingAddrOfOpDelete == null) { + continue; + } + + // if firsrVfunction is called before op delete then valid set of + // destructor/deleting destructor + if (callingAddrOfOpDelete.getOffset() > callingAddressOfFirstVfunction.getOffset()) { + recoveredClass.addDestructor(firstVfunction); + recoveredClass.addDeletingDestructor(secondVfunction); + } + + } + } + } + + private Address getCallingAddress(Function function, Function expectedCalledFunction) throws CancelledException { + + InstructionIterator instructions = function.getProgram().getListing().getInstructions(function.getBody(), true); + + while (instructions.hasNext()) { + monitor.checkCancelled(); + Instruction instruction = instructions.next(); + if (instruction.getFlowType().isCall()) { + + Function calledFunction = extendedFlatAPI.getReferencedFunction(instruction.getMinAddress(), false); + + if (calledFunction == null) { + continue; + } + if (calledFunction.equals(expectedCalledFunction)) { + return instruction.getAddress(); + } + } + } + return null; + + } + + private Address getCallingAddress(Function function, String expectedCalledFunctionName) throws CancelledException { + + InstructionIterator instructions = function.getProgram().getListing().getInstructions(function.getBody(), true); + + while (instructions.hasNext()) { + monitor.checkCancelled(); + Instruction instruction = instructions.next(); + if (instruction.getFlowType().isCall()) { + + Function calledFunction = extendedFlatAPI.getReferencedFunction(instruction.getMinAddress(), false); + if (calledFunction.getName().equals(expectedCalledFunctionName)) { + return instruction.getAddress(); + } + } + } + return null; + + } + + private void removeFromIndeterminateLists(List recoveredClasses, Function function) + throws CancelledException { + + for (RecoveredClass recoveredClass : recoveredClasses) { + monitor.checkCancelled(); + + recoveredClass.getIndeterminateInlineList().remove(function); + recoveredClass.getIndeterminateList().remove(function); + } + } + + private StructureDataType createClassTypeInfoStructure() throws CancelledException { StructureDataType classTypeInfoStructure = new StructureDataType(classDataTypesCategoryPath, - CLASS_TYPE_INFO_STRUCTURE, 0, dataTypeManager); + CLASS_TYPE_INFO_STRUCTURE, 0, dataTypeManager); CharDataType characterDT = new CharDataType(); - PointerTypedef classTypeInfoPtr = - new PointerTypedef(null, null, -1, program.getDataTypeManager(), componentOffset); + if (hasExternalRelocations()) { + PointerTypedef classTypeInfoPtr = new PointerTypedef(null, null, -1, program.getDataTypeManager(), + componentOffset); + classTypeInfoStructure.add(classTypeInfoPtr, "classTypeinfoPtr", null); + + } + else { + PointerTypedef classTypeInfoPtr = new PointerTypedef(null, PointerDataType.dataType, -1, + program.getDataTypeManager(), 0); + classTypeInfoStructure.add(classTypeInfoPtr, "classTypeinfoPtr", null); + } DataType charPointer = dataTypeManager.getPointer(characterDT); - classTypeInfoStructure.add(classTypeInfoPtr, "classTypeinfoPtr", null); classTypeInfoStructure.add(charPointer, "typeinfoName", null); classTypeInfoStructure.setPackingEnabled(true); @@ -1906,20 +3092,21 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { return classTypeInfoStructure; } - private StructureDataType createSiClassTypeInfoStructure( - StructureDataType classTypeInfoStructure) { + private StructureDataType createSiClassTypeInfoStructure(StructureDataType classTypeInfoStructure) + throws CancelledException { - StructureDataType siClassTypeInfoStructure = new StructureDataType( - classDataTypesCategoryPath, SI_CLASS_TYPE_INFO_STRUCTURE, 0, dataTypeManager); + StructureDataType siClassTypeInfoStructure = new StructureDataType(classDataTypesCategoryPath, + SI_CLASS_TYPE_INFO_STRUCTURE, 0, dataTypeManager); CharDataType characterDT = new CharDataType(); - PointerTypedef classTypeInfoPtr = - new PointerTypedef(null, null, -1, program.getDataTypeManager(), componentOffset); + + PointerTypedef classTypeInfoPtr = new PointerTypedef(null, null, -1, program.getDataTypeManager(), + componentOffset); + siClassTypeInfoStructure.add(classTypeInfoPtr, "classTypeinfoPtr", null); DataType charPointer = dataTypeManager.getPointer(characterDT); - siClassTypeInfoStructure.add(classTypeInfoPtr, "classTypeinfoPtr", null); siClassTypeInfoStructure.add(charPointer, "typeinfoName", null); DataType pointerToClassTypeInfoStruct = dataTypeManager.getPointer(classTypeInfoStructure); @@ -1930,38 +3117,33 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { return siClassTypeInfoStructure; } - private StructureDataType createBaseClassTypeInfoStructure( - StructureDataType classTypeInfoStructure) throws InvalidDataTypeException { + private StructureDataType createBaseClassTypeInfoStructure(StructureDataType classTypeInfoStructure) + throws InvalidDataTypeException { - StructureDataType baseclassTypeInfoStructure = new StructureDataType( - classDataTypesCategoryPath, BASE_CLASS_TYPE_INFO_STRUCTURE, 0, dataTypeManager); + StructureDataType baseclassTypeInfoStructure = new StructureDataType(classDataTypesCategoryPath, + BASE_CLASS_TYPE_INFO_STRUCTURE, 0, dataTypeManager); DataType classTypeInfoPointer = dataTypeManager.getPointer(classTypeInfoStructure); int offsetBitSize = 24; + DataType dataType = new LongDataType(); if (defaultPointerSize == 8) { offsetBitSize = 56; + dataType = new LongLongDataType(); } baseclassTypeInfoStructure.add(classTypeInfoPointer, "classTypeinfoPtr", null); if (program.getMemory().isBigEndian()) { - baseclassTypeInfoStructure.addBitField(LongDataType.dataType, offsetBitSize, - "baseClassOffset", null); - baseclassTypeInfoStructure.addBitField(BooleanDataType.dataType, 1, "isPublicBase", - null); - baseclassTypeInfoStructure.addBitField(BooleanDataType.dataType, 1, "isVirtualBase", - null); - baseclassTypeInfoStructure.addBitField(ByteDataType.dataType, 6, "unused", null); - } - else { - baseclassTypeInfoStructure.addBitField(BooleanDataType.dataType, 1, "isVirtualBase", - null); - baseclassTypeInfoStructure.addBitField(BooleanDataType.dataType, 1, "isPublicBase", - null); - baseclassTypeInfoStructure.addBitField(ByteDataType.dataType, 6, "unused", null); - baseclassTypeInfoStructure.addBitField(LongDataType.dataType, offsetBitSize, - "baseClassOffset", null); + baseclassTypeInfoStructure.addBitField(dataType, offsetBitSize, "baseClassOffset", "baseClassOffset"); + baseclassTypeInfoStructure.addBitField(dataType, 1, "isPublicBase", "isPublicBase"); + baseclassTypeInfoStructure.addBitField(dataType, 1, "isVirtualBase", "isVirtualBase"); + baseclassTypeInfoStructure.addBitField(dataType, 6, "unused", "unused"); + } else { + baseclassTypeInfoStructure.addBitField(dataType, 1, "isVirtualBase", "isVirtualBase"); + baseclassTypeInfoStructure.addBitField(dataType, 1, "isPublicBase", "isPublicBase"); + baseclassTypeInfoStructure.addBitField(dataType, 6, "unused", "unused"); + baseclassTypeInfoStructure.addBitField(dataType, offsetBitSize, "baseClassOffset", "baseClassOffset"); } baseclassTypeInfoStructure.setPackingEnabled(true); @@ -1970,73 +3152,63 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } - private StructureDataType createVmiClassTypeInfoStructure( - StructureDataType baseClassTypeInfoStructure, int numBaseClasses) { + private StructureDataType createVmiClassTypeInfoStructure(StructureDataType baseClassTypeInfoStructure, + int numBaseClasses) throws CancelledException { - StructureDataType vmiClassTypeInfoStructure = - new StructureDataType(classDataTypesCategoryPath, + StructureDataType vmiClassTypeInfoStructure = new StructureDataType(classDataTypesCategoryPath, VMI_CLASS_TYPE_INFO_STRUCTURE + numBaseClasses, 0, dataTypeManager); CharDataType characterDT = new CharDataType(); UnsignedIntegerDataType unsignedIntDT = new UnsignedIntegerDataType(); - PointerTypedef classTypeInfoPtr = - new PointerTypedef(null, null, -1, program.getDataTypeManager(), componentOffset); + + PointerTypedef classTypeInfoPtr = new PointerTypedef(null, null, -1, program.getDataTypeManager(), + componentOffset); + vmiClassTypeInfoStructure.add(classTypeInfoPtr, "classTypeinfoPtr", null); DataType charPointer = dataTypeManager.getPointer(characterDT); - vmiClassTypeInfoStructure.add(classTypeInfoPtr, "classTypeinfoPtr", null); vmiClassTypeInfoStructure.add(charPointer, "typeinfoName", null); vmiClassTypeInfoStructure.add(unsignedIntDT, "flags", null); vmiClassTypeInfoStructure.add(unsignedIntDT, "numBaseClasses", null); // make array of base class type info structs ArrayDataType baseClassArray = new ArrayDataType(baseClassTypeInfoStructure, numBaseClasses, - baseClassTypeInfoStructure.getLength()); - vmiClassTypeInfoStructure.add(baseClassArray, "baseClassPtrArray", null); + baseClassTypeInfoStructure.getLength()); + try { + vmiClassTypeInfoStructure.add(baseClassArray, "baseClassPtrArray", null); + } catch (IllegalArgumentException e) { + Msg.debug(baseClassArray, e); + } vmiClassTypeInfoStructure.setPackingEnabled(true); return vmiClassTypeInfoStructure; } - + + /** - * Method to add parents to the given gcc class - * @param recoveredClass the given class - * @param typeinfoAddress the address of the typeinfo + * Method to add parents to the given class + * + * @param recoveredClass the given class + * @param typeinfoAddress the address of the typeinfo * @return list of parents for the given class - * @throws Exception if cannot access the given typeinfo structure, one of its components, - * or it is not a vmi structure + * @throws CancelledException + * @throws Exception if cannot access the given typeinfo structure, one of its + * components, or it is not a vmi structure */ - private List addGccClassParentsFromVmiStruct(RecoveredClass recoveredClass, - Address typeinfoAddress) throws Exception { + private List addClassParentsAndFlagsForVmiClass(RecoveredClass recoveredClass, GccTypeinfo typeinfo) throws CancelledException{ + - Structure vmiTypeinfoStructure = getTypeinfoStructure(typeinfoAddress); - if (vmiTypeinfoStructure == null || - !vmiTypeinfoStructure.getName().contains(VMI_CLASS_TYPE_INFO_STRUCTURE)) { - throw new Exception( - "Could not get vmi base typeinfo structure at address " + typeinfoAddress); - } - - // process the inheritance flag - DataTypeComponent inheritanceFlagComponent = vmiTypeinfoStructure.getComponent(2); - int flagOffset = inheritanceFlagComponent.getOffset(); - DataType inheritanceFlagDataType = inheritanceFlagComponent.getDataType(); - MemBuffer buf = - new DumbMemBufferImpl(program.getMemory(), getAddress(typeinfoAddress, flagOffset)); - Scalar scalar = (Scalar) inheritanceFlagDataType.getValue(buf, - inheritanceFlagDataType.getDefaultSettings(), inheritanceFlagDataType.getLength()); - long inheritanceFlagValue = scalar.getUnsignedValue(); + long inheritanceFlagValue = typeinfo.getInheritanceFlagValue(); // 0x01: class has non-diamond repeated inheritance // 0x02: class is diamond shaped // add flag for non-diamond repeated and diamond shape types if (inheritanceFlagValue == 1) { if (DEBUG) { - Msg.debug(this, - "from typeinfo at address " + typeinfoAddress.toString() + " " + - recoveredClass.getClassNamespace().getName(true) + - " has non-diamond repeated inheritance"); + Msg.debug(this, "from typeinfo at address " + typeinfo.getAddress().toString() + " " + + recoveredClass.getClassNamespace().getName(true) + " has non-diamond repeated inheritance"); } } if (inheritanceFlagValue == 2) { @@ -2048,136 +3220,47 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { Map orderToParentMap = new HashMap(); Map parentToOffsetMap = new HashMap(); - DataTypeComponent numBaseClassesComponent = vmiTypeinfoStructure.getComponent(3); - int numBaseClassesOffset = numBaseClassesComponent.getOffset(); - DataType numBaseClassesDataType = numBaseClassesComponent.getDataType(); - buf = new DumbMemBufferImpl(program.getMemory(), - getAddress(typeinfoAddress, numBaseClassesOffset)); - scalar = (Scalar) numBaseClassesDataType.getValue(buf, - numBaseClassesDataType.getDefaultSettings(), numBaseClassesDataType.getLength()); - int numBaseClasses = (int) scalar.getUnsignedValue(); - - if (numBaseClasses < 0) { - throw new IllegalArgumentException("Could not process vmi class " + - recoveredClass.getName() + - " because getting the number of bases from the vmi typeinfo structure at address " + - typeinfoAddress.toString()); + List baseTypeinfos = typeinfo.getBaseTypeinfos(); + int numBaseClasses = baseTypeinfos.size(); + + boolean hasVirtualInheritance = false; + if(typeinfo.getNumAllVirtualBases() > 0) { + hasVirtualInheritance = true; } if (numBaseClasses > 1) { recoveredClass.setHasMultipleInheritance(true); recoveredClass.setHasSingleInheritance(false); - } - else { + } else { recoveredClass.setHasMultipleInheritance(false); recoveredClass.setHasSingleInheritance(true); + recoveredClass.setHasMultipleVirtualInheritance(hasVirtualInheritance); } - - // process the base class array - DataTypeComponent baseClassArrayComponent = vmiTypeinfoStructure.getComponent(4); - if (baseClassArrayComponent == null) { - throw new Exception( - "Could not get base class array in vmi structure at " + typeinfoAddress.toString()); - } - int baseClassArrayOffset = baseClassArrayComponent.getOffset(); - + List parentClassList = new ArrayList(); - int numParents = numBaseClasses; + int parentNum = 0; + for(BaseTypeinfo baseTypeinfo : baseTypeinfos) { + monitor.checkCancelled(); - for (int i = 0; i < numParents; i++) { - - // get parent from pointer to parent typeinfo - Address parentRefAddress = - getAddress(typeinfoAddress, baseClassArrayOffset + (i * 2 * defaultPointerSize)); - - RecoveredClass parentClass = getParentClassFromParentTypeInfoRef(parentRefAddress); + GccTypeinfo vmiParentTypeinfo = baseTypeinfo.getBaseTypeinfo(); + + RecoveredClass parentClass = getClass(vmiParentTypeinfo.getNamespace()); + if (parentClass == null) { - throw new Exception("Could not get parent class number " + (i + 1) + - " from typeinfo struct at " + typeinfoAddress.toString()); + throw new IllegalArgumentException("RecoveredClass should already exist for " + vmiParentTypeinfo.getNamespace().getName(true)); } - - if (DEBUG) { - Msg.debug(this, - recoveredClass.getName() + " adding vmi parent " + parentClass.getName()); - } - + updateClassWithParent(parentClass, recoveredClass); parentClassList.add(parentClass); - LongDataType longDT = new LongDataType(); + recoveredClass.addParentToBaseTypeMapping(parentClass, baseTypeinfo.isVirtualBase()); - // get public/virtual/offset flag - Address flagAddress = getAddress(typeinfoAddress, - baseClassArrayOffset + (i * 2 * defaultPointerSize + defaultPointerSize)); - - buf = new DumbMemBufferImpl(program.getMemory(), flagAddress); - - Scalar value = - (Scalar) longDT.getValue(buf, longDT.getDefaultSettings(), defaultPointerSize); - - long publicVirtualOffsetFlag = value.getSignedValue(); - - //The low-order byte of __offset_flags contains flags, as given by the masks - //from the enumeration __offset_flags_masks: - - //0x1: Base class is virtual - //0x2: Base class is public - - boolean isVirtual = false; - boolean isPublic = false; - - long virtualMask = 0x1L; - long publicMask = 0x2L; - long offsetMask; - if (defaultPointerSize == 4) { - offsetMask = 0xffffff00L; - - } - else { - offsetMask = 0xffffffffffffff00L; - } - - if ((publicVirtualOffsetFlag & virtualMask) == 1) { - isVirtual = true; - } - - if (recoveredClass.hasMultipleInheritance()) { - recoveredClass.setHasMultipleVirtualInheritance(isVirtual); - } - - recoveredClass.addParentToBaseTypeMapping(parentClass, isVirtual); - - recoveredClass.setInheritsVirtualAncestor(isVirtual); - - if (((publicVirtualOffsetFlag & publicMask) >> 1) == 1) { - isPublic = true; - } - - parentClass.setIsPublicClass(isPublic); - - // from doc: - //All but the lower 8 bits of __offset_flags are a signed offset. For a - //non-virtual base, this is the offset in the object of the base subobject. - //For a virtual base, this is the offset in the virtual table of the - //virtual base offset for the virtual base referenced (negative). - long offset = (publicVirtualOffsetFlag & offsetMask) >> 8; - - 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); - parentToOffsetMap.put(parentClass, offset); - - continue; - - } - - if (DEBUG) { - Msg.debug(this, recoveredClass.getName() + " has " + numParents + " parents"); + recoveredClass.setInheritsVirtualAncestor(hasVirtualInheritance); + parentClass.setIsPublicClass(baseTypeinfo.isPublicBase()); + + orderToParentMap.put(parentNum++, parentClass); + parentToOffsetMap.put(parentClass, baseTypeinfo.getOffset()); } classToParentOrderMap.put(recoveredClass, orderToParentMap); @@ -2186,272 +3269,324 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { return parentClassList; } + + - /** - * Get the parent class given the typeinfo address of an Si class - * @param typeinfoAddress the given Si class's typeinfo Address - * @return the parent class - * @throws Exception if cannot access parent's type info reference address or if could not get - * the parent class - */ - private RecoveredClass getSiClassParent(Address typeinfoAddress) throws Exception { + private Address findSpecialVtable(GccTypeinfo specialTypeinfo, List specialTypeinfos) + throws CancelledException { - int offset = defaultPointerSize * 2; + String namespaceName = specialTypeinfo.getNamespace().getName(); + String mangledNamespaceString = specialTypeinfo.getMangledNamespaceString(); - Address parentTypeinfoRef = getAddress(typeinfoAddress, offset); - if (parentTypeinfoRef == null) { + // try finding with normal symbol name and namespace + Symbol vtableSymbol = getSymbolInNamespaces(SPECIAL_CLASS_NAMESPACE, namespaceName, VTABLE_LABEL); + if (vtableSymbol == null) { + // then try finding with mangled symbol + vtableSymbol = findAndReturnDemangledSymbol(MANGLED_VTABLE_PREFIX + mangledNamespaceString, + SPECIAL_CLASS_NAMESPACE, namespaceName, VTABLE_LABEL); - throw new Exception("Could not access address " + typeinfoAddress.toString() + - " plus offset " + offset); + // then try finding top of special vtable by finding ref to special typeinfo + if (vtableSymbol == null) { + Address vtableAddress = findSpecialVtableUsingSpecialTypeinfo(specialTypeinfo.getAddress(), + specialTypeinfos); - } + if (vtableAddress == null) { + return null; + } - RecoveredClass parentClass = getParentClassFromParentTypeInfoRef(parentTypeinfoRef); + try { + vtableSymbol = symbolTable.createLabel(vtableAddress, VTABLE_LABEL, specialTypeinfo.getNamespace(), + SourceType.ANALYSIS); + api.setPlateComment(vtableAddress, "vtable for " + specialTypeinfo.getNamespace()); - return parentClass; + } catch (InvalidInputException e) { + vtableSymbol = null; + } - } - - /** - * Method to return the parent class given a reference to the parent class's typeinfo struct - * @param parentTypeinfoRef the given parent typeinfo reference - * @return the associated parent class - */ - private RecoveredClass getParentClassFromParentTypeInfoRef(Address parentTypeinfoRef) { - - Address parentAddress = extendedFlatAPI.getSingleReferencedAddress(parentTypeinfoRef); - if (parentAddress == null) { - return null; - } - Symbol parentSymbol = symbolTable.getPrimarySymbol(parentAddress); - if (parentSymbol == null) { - return null; - } - Namespace parentNamespace = parentSymbol.getParentNamespace(); - if (parentNamespace == null) { - return null; - } - RecoveredClass parentClass = getClass(parentNamespace); - - if (parentClass == null) { - return null; - } - return parentClass; - } - - /** - * Method to find the (up to three) special gcc vtables and replace the incorrectly made array - * with the correct data types. Also creates typeinfo 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, InvalidInputException { - - class_type_info_vtable = findSpecialVtable("__cxxabiv1", "__class_type_info"); - class_type_info = null; - if (class_type_info_vtable == null) { - Msg.debug(this, "__class_type_info vtable not found --> no classes without parents"); - } - else { - class_type_info = createSpecialVtable(class_type_info_vtable); - if (class_type_info == null) { - Msg.debug(this, - "__class_type_info typeinfo not found -- cannot continue gcc rtti processing"); - return false; } } - - si_class_type_info = null; - si_class_type_info_vtable = findSpecialVtable("__cxxabiv1", "__si_class_type_info"); - if (si_class_type_info_vtable == null) { - Msg.debug(this, "__si_class_type_info vtable not found --> no single parent classes"); + if (vtableSymbol != null) { + return vtableSymbol.getAddress(); } - else { - si_class_type_info = createSpecialVtable(si_class_type_info_vtable); - if (si_class_type_info == null) { - Msg.debug(this, - "__si_class_type_info typeinfo not found -- cannot continue gcc rtti " + - "processing"); - return false; - } - } - - vmi_class_type_info_vtable = findSpecialVtable("__cxxabiv1", "__vmi_class_type_info"); - vmi_class_type_info = null; - if (vmi_class_type_info_vtable == null) { - Msg.debug(this, "__vmi_class_type_info vtable not found --> no multi-parent classes"); - } - else { - vmi_class_type_info = createSpecialVtable(vmi_class_type_info_vtable); - if (vmi_class_type_info == null) { - Msg.debug(this, - "__vmi_class_type_info typeinfo not found -- cannot continue gcc rtti " + - "processing"); - return false; - } - } - - if (class_type_info_vtable == null && si_class_type_info_vtable == null && - vmi_class_type_info_vtable == null) { - Msg.debug(this, - "Since there are no class typeinfo tables this program does not appear to have " + - "RTTI."); - return false; - } - return true; - } - - /** - * Method to find the next reference to a typeinfo symbol after the given address - * @param startAddress the address to start looking from - * @return the address of the next typeinfo address after the given address - */ - private Address findNextTypeinfoRef(Address startAddress) { - - int offset = 0; - - Address address = extendedFlatAPI.getAddress(startAddress, offset); - - MemoryBlock currentMemoryBlock = program.getMemory().getBlock(startAddress); - - while (address != null && currentMemoryBlock.contains(address)) { - - Symbol symbol = symbolTable.getPrimarySymbol(address); - // if the symbol we find is not a default symbol - // because we have reached the end of the item we are searching - if (!address.equals(startAddress) && symbol != null && - symbol.getSource() != SourceType.DEFAULT) { - return null; - } - - Address possibleTypeinfo = extendedFlatAPI.getPointer(address); - if (possibleTypeinfo == null) { - offset += defaultPointerSize; - address = extendedFlatAPI.getAddress(startAddress, offset); - continue; - } - - Symbol possibleTypeinfoSymbol = symbolTable.getPrimarySymbol(possibleTypeinfo); - if (possibleTypeinfoSymbol != null && - possibleTypeinfoSymbol.getName().equals("typeinfo")) { - return address; - } - offset += defaultPointerSize; - address = extendedFlatAPI.getAddress(startAddress, offset); - - } - return null; } - /** - * Method to process the primary vtable for each "vtable" label - * @return the vftable Address in the vtable - * @throws Exception if Data cannot be created - */ - private List findVftablesFromVtables() throws Exception { + private List findSpecialVtables(List specialTypeinfos) throws Exception { - List vftableSymbols = new ArrayList(); + List specialVtables = new ArrayList(); - // find all vtable symbols - List listOfVtableSymbols = extendedFlatAPI.getListOfSymbolsInAddressSet( - program.getAddressFactory().getAddressSet(), VTABLE_LABEL, true); + for (GccTypeinfo specialTypeinfo : specialTypeinfos) { + monitor.checkCancelled(); - Iterator vtableIterator = listOfVtableSymbols.iterator(); - while (vtableIterator.hasNext()) { + Address vtableAddress = findSpecialVtable(specialTypeinfo, specialTypeinfos); - monitor.checkCanceled(); - - Symbol vtableSymbol = vtableIterator.next(); - Namespace vtableNamespace = vtableSymbol.getParentNamespace(); - Address vtableAddress = vtableSymbol.getAddress(); - - // skip the special tables - if (vtableAddress.equals(class_type_info_vtable) || - vtableAddress.equals(si_class_type_info_vtable) || - vtableAddress.equals(vmi_class_type_info_vtable)) { + if (vtableAddress == null) { continue; } - Data vtableData = api.getDataAt(vtableAddress); - if (vtableData == null) { - continue; - } - - // find the special type info ref - Address typeinfoAddress = findNextTypeinfoRef(vtableAddress); - if (typeinfoAddress == null) { - if (DEBUG) { - Msg.debug(this, vtableAddress.toString() + " " + vtableNamespace.getName() + - " vtable has no typeinfo ref"); + SpecialVtable specialVtable = createSpecialVtable(vtableAddress, specialTypeinfo); + if (specialVtable != null) { + specialVtables.add(specialVtable); + specialTypeinfo.setVtableAddress(vtableAddress); + if (!specialVtable.isExternal()) { + specialVtable.applyVtableData(); + vtableToSizeMap.put(specialVtable.getAddress(), specialVtable.getLength()); + createVtableLabel(specialVtable); + createVtableComment(specialVtable); + createVfunctionSymbol(specialVtable); } - continue; - } - - Address vftableAddress = - extendedFlatAPI.getAddress(typeinfoAddress, defaultPointerSize); - // no valid address here so continue - if (vftableAddress == null) { - //createNewClass(vtableNamespace, false); - // if so should also add to no vftable class - continue; - } - Symbol vftableSymbol = symbolTable.getPrimarySymbol(vftableAddress); - if (vftableSymbol == null) { - continue; - } - if (vftableSymbol.getName().equals(VFTABLE_LABEL)) { - vftableSymbols.add(vftableSymbol); } } - return vftableSymbols; + return specialVtables; } - /** - * Method to check if given typeinfo is one of the three special ones - * @param address the given typeinfo address - * @return true if it is a special one, false otherwise + /* + * Method to find special vtable using special typeinfo references. This + * assumption that vtable is defaultPtrSize above ref to single specialTypeinfo + * ref only works for special typeinfos/vtables. Regular ones can have variable + * len between the two */ - private boolean isSpecialTypeinfo(Address address) { - if (address.equals(class_type_info) || address.equals(si_class_type_info) || - address.equals(vmi_class_type_info)) { - return true; - } - return false; - } - - private boolean isSpecialVtable(Address address) { - if (address.equals(class_type_info_vtable) || address.equals(si_class_type_info_vtable) || - address.equals(vmi_class_type_info_vtable)) { - return true; - } - return false; - } - - private void createClassesFromTypeinfoSymbols(List typeinfoSymbols) + private Address findSpecialVtableUsingSpecialTypeinfo(Address typeinfoAddress, List specialTypeinfos) throws CancelledException { - Iterator typeinfoIterator = typeinfoSymbols.iterator(); - while (typeinfoIterator.hasNext()) { + List
referencesTo = getAllReferencesTo(typeinfoAddress); - monitor.checkCanceled(); + if (referencesTo.isEmpty()) { + return null; + } - Symbol typeinfoSymbol = typeinfoIterator.next(); - Address typeinfoAddress = typeinfoSymbol.getAddress(); + // special typeinfos are all 3 * defaultPtrSize long if they are contained in + // internal memory otherwise they are 1 defaultPointerSize long + int specialTypeinfoLen = 3 * defaultPointerSize; - // skip the typeinfo symbols from the three special typeinfos - if (isSpecialTypeinfo(typeinfoAddress)) { + // create an address set containing addresses of the special typeinfos + AddressSet specialTypeinfoAddrSet = new AddressSet(); + for (GccTypeinfo specialTypeinfo : specialTypeinfos) { + Address start = specialTypeinfo.getAddress(); + Address end = start.add(defaultPointerSize); + if (specialTypeinfo.isInProgramMemory()) { + end = start.add(specialTypeinfoLen); + } + specialTypeinfoAddrSet.add(start, end); + + } + + // use the address set created to weed out references to the given typeinfo from special + // typeinofs we only want references to the given typeinfo from its associated vtable + List
possibleRefsInVtable = new ArrayList
(); + + for (Address refTo : referencesTo) { + monitor.checkCancelled(); + + if (specialTypeinfoAddrSet.contains(refTo)) { continue; } - // check for EXTERNAL block and look for specialTypeinfoRef there - // if fix works, put external block error message and to contact us - if (hasExternalBlock() && isSpecialVtable(typeinfoAddress)) { + possibleRefsInVtable.add(refTo); + } + if (possibleRefsInVtable.size() != 1) { + return null; + } + + Address typeinfoRef = possibleRefsInVtable.get(0); + Address vtableAddress = typeinfoRef.subtract(defaultPointerSize); + return vtableAddress; + } + + private Symbol findTypeinfoUsingMangledString(String mangledNamespaceString) throws CancelledException { + + Address findSingleMangledString = findSingleMangledString(mangledNamespaceString); + if (findSingleMangledString == null) { + return null; + } + + // get single reference to it + Address typeinfoNameRef = getSingleReferenceTo(findSingleMangledString); + + if (typeinfoNameRef == null) { + return null; + } + + Address typeinfoAddress = typeinfoNameRef.subtract(defaultPointerSize); + + mangledNamespaceString = MANGLED_STRING_PREFIX + mangledNamespaceString; + + try { + symbolTable.createLabel(findSingleMangledString, mangledNamespaceString, globalNamespace, + SourceType.ANALYSIS); + } catch (InvalidInputException e) { + + Msg.debug(this, "Could not make symbol for mangled string at " + findSingleMangledString); + return null; + } + + // demangle the symbol + DemanglerCmd cmd = new DemanglerCmd(findSingleMangledString, mangledNamespaceString); + cmd.applyTo(program, monitor); + + // get the newly created symbol to get the namespace + Symbol typeinfoNameSymbol = symbolTable.getPrimarySymbol(findSingleMangledString); + Namespace namespace = typeinfoNameSymbol.getParentNamespace(); + + Symbol typeinfoSymbol; + try { + typeinfoSymbol = symbolTable.createLabel(typeinfoAddress, "typeinfo", namespace, SourceType.ANALYSIS); + api.setPlateComment(typeinfoAddress, "typeinfo for " + namespace); + } catch (InvalidInputException e) { + Msg.debug(this, "Could not make typeinfo symbol at " + typeinfoAddress); + return null; + } + + return typeinfoSymbol; + } + + private Address findSingleMangledString(String mangledString) { + + Address[] findBytes = extendedFlatAPI.findBytes(null, mangledString, 1); + if (findBytes.length != 1) { + return null; + } + return findBytes[0]; + + } + + private Address getSingleReferenceTo(Address address) throws CancelledException { + + Set
refs = new HashSet
(); + + ReferenceManager referenceManager = program.getReferenceManager(); + ReferenceIterator referencesTo = referenceManager.getReferencesTo(address); + while (referencesTo.hasNext()) { + monitor.checkCancelled(); + + Reference next = referencesTo.next(); + + Address ref = next.getFromAddress(); + + // skip refs without an address + if (ref == Address.EXT_FROM_ADDRESS) { continue; } - Namespace classNamespace = typeinfoSymbol.getParentNamespace(); + refs.add(ref); + } + + // look for direct refs now + if (!address.isExternalAddress()) { + Set
dirRefSet = directRefMap.get(address); + if (dirRefSet != null) { + List
directRefs = new ArrayList
(dirRefSet); + refs.addAll(directRefs); + } + } + + List
refList = new ArrayList
(refs); + + if (refList.size() == 1) { + return refList.get(0); + } + + return null; + + } + + private List
getAllReferencesTo(Address address) throws CancelledException { + + Set
refs = new HashSet
(); + + ReferenceManager referenceManager = program.getReferenceManager(); + ReferenceIterator referencesTo = referenceManager.getReferencesTo(address); + while (referencesTo.hasNext()) { + monitor.checkCancelled(); + + Reference next = referencesTo.next(); + + // if external relocations there will be offset ref and that's ok + // the ones to skip are offset in the middle of defined data + if (!inExternalBlock(address) && next.isOffsetReference()) { + continue; + } + if (next.isEntryPointReference()) { + continue; + } + + Address ref = next.getFromAddress(); + + // skip refs without an address + if (ref == Address.EXT_FROM_ADDRESS) { + continue; + } + + refs.add(ref); + } + + // look for direct refs now + Set
directRefs = directRefMap.get(address); + if (directRefs != null) { + refs.addAll(directRefs); + } + + List
refList = new ArrayList
(refs); + + return refList; + + } + + List
findDirectRefsTo(Address address) throws CancelledException { + + byte[] bytes = ProgramMemoryUtil.getDirectAddressBytes(program, address); + List
foundRefs = new ArrayList
(); + + Address start = program.getMinAddress(); + while (start.compareTo(program.getMaxAddress()) < 0) { + + monitor.checkCancelled(); + + Address found = program.getMemory().findBytes(start, bytes, null, true, monitor); + if (found == null) { + break; + } + foundRefs.add(found); + + start = found.add(defaultPointerSize); + + } + + return foundRefs; + } + + /** + * Create a map of addresses to a set of addresses that reference each address + * + * @param refPairs list of reference address pairs + * @throws CancelledException if cancelled + */ + public void createGlobalDirectRefMap(List refPairs) throws CancelledException { + + for (ReferenceAddressPair refPair : refPairs) { + monitor.checkCancelled(); + + Address referencedAddress = refPair.getDestination(); + Address fromAddress = refPair.getSource(); + Set
dirRefs = directRefMap.get(referencedAddress); + if (dirRefs == null) { + dirRefs = new HashSet
(); + } + dirRefs.add(fromAddress); + directRefMap.put(referencedAddress, dirRefs); + } + + } + + private void createClassesFromTypeinfos(List typeinfos) throws CancelledException { + + for (GccTypeinfo typeinfo : typeinfos) { + + monitor.checkCancelled(); + + Address typeinfoAddress = typeinfo.getAddress(); + + Namespace classNamespace = typeinfo.getNamespace(); RecoveredClass recoveredClass = getClass(classNamespace); @@ -2471,38 +3606,18 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { recoveredClasses.add(recoveredClass); } - Address specialTypeinfoRef = - extendedFlatAPI.getSingleReferencedAddress(typeinfoAddress); - if (specialTypeinfoRef == null) { - if (DEBUG) { - Msg.debug(this, - "No special typeinfo reference found. Cannot process typeinfo struct at " + - typeinfoAddress.toString()); - } + String typeinfoStructureType = typeinfoToStructuretypeMap.get(typeinfoAddress); + if (typeinfoStructureType == null) { + + // skip if not a class type info struct + Msg.debug(this, typeinfoAddress + " has no structure type mapping"); continue; } - if (!isSpecialTypeinfo(specialTypeinfoRef)) { - // check for EXTERNAL block and look for specialTypeinfoRef there - // if fix works, put external block error message and to contact us - if (!hasExternalBlock()) { - continue; - } - // use referenced vtable symbol name instead since when in EXTERNAL block - // since can't get at the typeinfo ref in that block - if (!isSpecialVtable(specialTypeinfoRef)) { - continue; - } - - } - - // per docs those on this list - // have no bases (ie parents), and is also a base type for the other two class type - // representations ie (si and vmi) - if (specialTypeinfoRef.equals(class_type_info) || - specialTypeinfoRef.equals(class_type_info_vtable)) { - - nonInheritedGccClasses.add(recoveredClass); + // per docs those on this list have no bases (ie parents), and is also a base type + // for the other two class type representations ie (si and vmi) + if (typeinfoStructureType.equals(CLASS_TYPE_INFO_STRUCTURE)) { + nonInheritedClasses.add(recoveredClass); recoveredClass.setHasSingleInheritance(true); recoveredClass.setHasParentClass(false); recoveredClass.setInheritsVirtualAncestor(false); @@ -2511,49 +3626,75 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // per docs those on this list are // classes containing only a single, public, non-virtual base at offset zero - if (specialTypeinfoRef.equals(si_class_type_info) || - specialTypeinfoRef.equals(si_class_type_info_vtable)) { - - singleInheritedGccClasses.add(recoveredClass); + if (typeinfoStructureType.equals(SI_CLASS_TYPE_INFO_STRUCTURE)) { + singleInheritedClasses.add(recoveredClass); recoveredClass.setHasSingleInheritance(true); recoveredClass.setInheritsVirtualAncestor(false); continue; } - if (specialTypeinfoRef.equals(vmi_class_type_info) || - specialTypeinfoRef.equals(vmi_class_type_info_vtable)) { - - multiAndOrVirtuallyInheritedGccClasses.add(recoveredClass); - // not necessarily multiple - maybe just a single virtual ancestor or maybe a single - // non-public one - + // not necessarily multiple - maybe just a single virtual ancestor or maybe a + // single non-public one + if (typeinfoStructureType.equals(VMI_CLASS_TYPE_INFO_STRUCTURE)) { + multiAndOrVirtuallyInheritedClasses.add(recoveredClass); } } } + + private void updateClassWithVfunctions(List recoveredClasses, List vtables) throws Exception { + + for (RecoveredClass recoveredClass : recoveredClasses) { + + monitor.checkCancelled(); + Namespace classNamespace = recoveredClass.getClassNamespace(); + + Vtable classVtable = getVtable(vtables, classNamespace); + + if (classVtable == null) { + Msg.debug(this, "No vtable for class: " + classNamespace.getName()); + return; + } + + Address vftableAddress = classVtable.getVfunctionTop(); + if (vftableAddress == null) { + return; + } + + Symbol vftableSymbol = symbolTable.getPrimarySymbol(vftableAddress); + + updateClassWithVftable(recoveredClass, vftableSymbol, true, false); + + // For now just assume simple case + // will have to refactor helper to handle gcc better + recoveredClass.addClassOffsetToVftableMapping(0, vftableAddress); + } + } /** - * Use information from RTTI Base class Arrays to create class hierarchy lists and maps + * 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 createClassHierarchyListAndMap() throws CancelledException, Exception { Iterator recoveredClassIterator = recoveredClasses.iterator(); while (recoveredClassIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = recoveredClassIterator.next(); List classHierarchyList = new ArrayList(); // no parent case - if (nonInheritedGccClasses.contains(recoveredClass)) { - classHierarchyList = getGccNoClassHierarchy(recoveredClass); + if (nonInheritedClasses.contains(recoveredClass)) { + classHierarchyList = getNoClassHierarchy(recoveredClass); recoveredClass.setClassHierarchy(classHierarchyList); continue; } // case where there is all single inheritance in a class ancestry chain - if (singleInheritedGccClasses.contains(recoveredClass)) { - classHierarchyList = getGccSingleClassHierarchy(recoveredClass); + if (singleInheritedClasses.contains(recoveredClass)) { + classHierarchyList = getSingleClassHierarchy(recoveredClass); recoveredClass.setClassHierarchy(classHierarchyList); continue; } @@ -2562,15 +3703,15 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { recoveredClassIterator = recoveredClasses.iterator(); while (recoveredClassIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = recoveredClassIterator.next(); List classHierarchyList = new ArrayList(); // once all the non and single inheritance ones are created, create the multi ones // case where there is multi-inheritance somewhere in the chain - if (multiAndOrVirtuallyInheritedGccClasses.contains(recoveredClass)) { - classHierarchyList = getGccMultiClassHierarchy(recoveredClass); + if (multiAndOrVirtuallyInheritedClasses.contains(recoveredClass)) { + classHierarchyList = getMultiClassHierarchy(recoveredClass); recoveredClass.setClassHierarchy(classHierarchyList); } } @@ -2578,25 +3719,24 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // create parent class hierarchy maps recoveredClassIterator = recoveredClasses.iterator(); while (recoveredClassIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = recoveredClassIterator.next(); List parentList = recoveredClass.getParentList(); Iterator parentIterator = parentList.iterator(); while (parentIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass parentClass = parentIterator.next(); - recoveredClass.addClassHierarchyMapping(parentClass, - parentClass.getClassHierarchy()); + recoveredClass.addClassHierarchyMapping(parentClass, parentClass.getClassHierarchy()); } } // update the inherits virtual ancestor flag using ancestors - previously was only done for - // parents but now have all classes with flag set for direct parent so can get the other + // parents but now have all classes with flag set for direct parent so can get the other // ancestors too recoveredClassIterator = recoveredClasses.iterator(); while (recoveredClassIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = recoveredClassIterator.next(); @@ -2618,7 +3758,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { List classHierarchy = recoveredClass.getClassHierarchy(); Iterator classIterator = classHierarchy.iterator(); while (classIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass ancestor = classIterator.next(); if (ancestor.inheritsVirtualAncestor()) { return true; @@ -2629,10 +3769,11 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { /** * Create the class hierarchy list for a class with no inheritance + * * @param recoveredClass the given class * @return the class hierarchy list for the given class with no inheritance */ - private List getGccNoClassHierarchy(RecoveredClass recoveredClass) { + private List getNoClassHierarchy(RecoveredClass recoveredClass) { List classHierarchyList = new ArrayList(); classHierarchyList.add(recoveredClass); return classHierarchyList; @@ -2640,12 +3781,13 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { /** * Create the class hierarchy for a class with only single inheritance parents + * * @param recoveredClass the given class - * @return the class hierarchy for the given class with only single inheritance parents + * @return the class hierarchy for the given class with only single inheritance + * parents * @throws CancelledException if cancelled */ - List getGccSingleClassHierarchy(RecoveredClass recoveredClass) - throws CancelledException { + List getSingleClassHierarchy(RecoveredClass recoveredClass) throws CancelledException { List classHierarchyList = new ArrayList(); @@ -2653,7 +3795,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { classHierarchyList.add(currentClass); while (currentClass.hasParentClass()) { - monitor.checkCanceled(); + monitor.checkCancelled(); currentClass = currentClass.getParentList().get(0); classHierarchyList.add(currentClass); } @@ -2662,12 +3804,13 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { /** * Create the class hierarchy list for a class with multiple inheritance + * * @param recoveredClass the given class - * @return the class hierarchy list for the given class with multiple inheritance + * @return the class hierarchy list for the given class with multiple + * inheritance * @throws CancelledException if cancelled */ - List getGccMultiClassHierarchy(RecoveredClass recoveredClass) - throws CancelledException { + List getMultiClassHierarchy(RecoveredClass recoveredClass) throws CancelledException { List classHierarchyList = new ArrayList(); @@ -2676,100 +3819,45 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { List parentList = recoveredClass.getParentList(); Iterator parentIterator = parentList.iterator(); while (parentIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass parentClass = parentIterator.next(); - if (nonInheritedGccClasses.contains(parentClass)) { + if (nonInheritedClasses.contains(parentClass)) { classHierarchyList.addAll(parentClass.getClassHierarchy()); continue; } - if (singleInheritedGccClasses.contains(parentClass)) { + if (singleInheritedClasses.contains(parentClass)) { classHierarchyList.addAll(parentClass.getClassHierarchy()); continue; } - if (multiAndOrVirtuallyInheritedGccClasses.contains(parentClass)) { - classHierarchyList.addAll(getGccMultiClassHierarchy(parentClass)); + if (multiAndOrVirtuallyInheritedClasses.contains(parentClass)) { + classHierarchyList.addAll(getMultiClassHierarchy(parentClass)); } } return classHierarchyList; } - /** - * Method to create a series of long data types from the given start address to the given end - * 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) throws CancelledException, Exception { - - LongDataType longDT = new LongDataType(); - int offset = 0; - Address address = start; - while (address != null && !address.equals(end)) { - - api.clearListing(address, address.add(defaultPointerSize - 1)); - api.createData(address, longDT); - offset += defaultPointerSize; - address = getAddress(start, offset); - } - - } - /** * Method to get address at address + offset + * * @param address the given address - * @param offset the given offset + * @param offset the given offset * @return the address at address + offset or null if it doesn't exist */ private Address getAddress(Address address, int offset) { try { Address newAddress = address.add(offset); return newAddress; - } - catch (AddressOutOfBoundsException e) { + } catch (AddressOutOfBoundsException e) { return null; } } - private int getNumFunctionPointers(Address topAddress, boolean allowNullFunctionPtrs, - boolean allowDefaultRefsInMiddle) throws CancelledException { - - int numFunctionPointers = 0; - Address address = topAddress; - MemoryBlock currentBlock = program.getMemory().getBlock(topAddress); - - boolean stillInCurrentTable = true; - while (address != null && currentBlock.contains(address) && stillInCurrentTable && - (isPossibleFunctionPointer(address) || - (allowNullFunctionPtrs && isPossibleNullPointer(address)))) { - - numFunctionPointers++; - address = address.add(defaultPointerSize); - Symbol symbol = api.getSymbolAt(address); - if (symbol == null) { - continue; - } - // never let non-default refs in middle - if (symbol.getSource() != SourceType.DEFAULT) { - stillInCurrentTable = false; - } - - // if it gets here it is default - if (!allowDefaultRefsInMiddle) { - stillInCurrentTable = false; - } - } - - return numFunctionPointers; - - } - /** - * Method to determine if there are enough zeros to make a null poihnter and no references into - * or out of the middle + * Method to determine if there are enough zeros to make a null poihnter and no + * references into or out of the middle + * * @param address the given address * @return true if the given address could be a valid null pointer, false if not */ @@ -2782,12 +3870,31 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { /** * Method to determine if the given address contains a possible function pointer + * * @param address the given address - * @return true if the given address contains a possible function pointer or false otherwise + * @return true if the given address contains a possible function pointer or + * false otherwise + * @throws CancelledException if cancelled */ - private boolean isPossibleFunctionPointer(Address address) { + private boolean isPossibleFunctionPointer(Address address) throws CancelledException { + + // TODO: make one that works for all casea in helper + + long longValue = extendedFlatAPI.getLongValueAt(address); + + Register lowBitCodeMode = program.getRegister("LowBitCodeMode"); + if (lowBitCodeMode != null) { + longValue = longValue & ~0x1; + } + + Address possibleFunctionPointer = null; + + try { + possibleFunctionPointer = address.getNewAddress(longValue); + } catch (AddressOutOfBoundsException e) { + return false; + } - Address possibleFunctionPointer = extendedFlatAPI.getPointer(address); if (possibleFunctionPointer == null) { return false; } @@ -2796,14 +3903,69 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { if (function != null) { return true; } + + AddressSetView executeSet = program.getMemory().getExecuteSet(); + + if (!executeSet.contains(possibleFunctionPointer)) { + return false; + } + + Instruction instruction = api.getInstructionAt(possibleFunctionPointer); + if (instruction != null) { + api.createFunction(possibleFunctionPointer, null); + return true; + + } + + boolean disassemble = api.disassemble(possibleFunctionPointer); + if (disassemble) { + + // check for the case where there is conflicting data at the thumb offset function + // pointer and if so clear the data and redisassemble and remove the bad bookmark + long originalLongValue = extendedFlatAPI.getLongValueAt(address); + if (originalLongValue != longValue) { + Address offsetPointer = address.getNewAddress(originalLongValue); + if (api.getDataAt(offsetPointer) != null) { + api.clearListing(offsetPointer); + disassemble = api.disassemble(address); + + Bookmark bookmark = getBookmarkAt(possibleFunctionPointer, BookmarkType.ERROR, "Bad Instruction", + "conflicting data"); + if (bookmark != null) { + api.removeBookmark(bookmark); + } + } + } + + api.createFunction(possibleFunctionPointer, null); + return true; + } return false; } + private Bookmark getBookmarkAt(Address address, String bookmarkType, String category, String commentContains) + throws CancelledException { + + Bookmark[] bookmarks = program.getBookmarkManager().getBookmarks(address); + + for (Bookmark bookmark : bookmarks) { + monitor.checkCancelled(); + + if (bookmark.getType().getTypeString().equals(bookmarkType) && bookmark.getCategory().equals(category) + && bookmark.getComment().contains(commentContains)) { + return bookmark; + } + } + return null; + } + /** - * Method to call create and apply class structures method starting with top parent classes - * and non-virtual classes then the children and their children until all classes are processed. + * Method to call create and apply class structures method starting with top + * parent classes and non-virtual classes then the children and their children + * until all classes are processed. + * * @throws CancelledException when cancelled - * @throws Exception if issue creating data + * @throws Exception if issue creating data */ private void createAndApplyClassStructures() throws CancelledException, Exception { @@ -2813,7 +3975,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // first process all the classes with no parents while (recoveredClassIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = recoveredClassIterator.next(); @@ -2841,7 +4003,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { int numLoops = 0; while (!listOfClasses.isEmpty()) { - monitor.checkCanceled(); + monitor.checkCancelled(); // put in stop gap measure in case some classes never get all // parents processed for some reason @@ -2855,7 +4017,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { RecoveredClass recoveredClass = recoveredClassIterator.next(); - monitor.checkCanceled(); + monitor.checkCancelled(); if (!listOfClasses.contains(recoveredClass)) { continue; } @@ -2872,41 +4034,55 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } /** - * Method to create all the class data types for the current class, name all the class - * functions, and put them all into the class namespace + * Method to create all the class data types for the current class, name all the + * class functions, and put them all into the class namespace + * * @param recoveredClass current class * @throws CancelledException when cancelled - * @throws Exception naming exception + * @throws Exception naming exception */ - private void processDataTypes(RecoveredClass recoveredClass) - throws CancelledException, Exception { + private void processDataTypes(RecoveredClass recoveredClass) throws CancelledException, Exception { - // 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."); - } + // if recovered class is a special typeinfo class skip it + if (recoveredClass.getName().endsWith("_class_type_info")) { + Msg.debug(this, "Not creating class data type for " + recoveredClass.getClassNamespace().getName(true) + + " because it is one of the special typeinfo classes."); return; } + // can't handle creating class data types for classes with virtual parents yet + if (recoveredClass.inheritsVirtualAncestor()) { + 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; + } + + // skip any classes that have special typeinfo class parents + if (recoveredClass.hasParentClass()) { + List parentList = recoveredClass.getParentList(); + for (RecoveredClass parent : parentList) { + monitor.checkCancelled(); + if (parent.getName().endsWith("_class_type_info")) { + Msg.debug(this, + "Not creating class data type for " + recoveredClass.getClassNamespace().getName(true) + + " because it has a parent that is one of the special typeinfo classes."); + return; + } + } + } + // can't handle creating class data types for diamond shaped classes yet if (recoveredClass.isDiamondShaped()) { - if (DEBUG) { - Msg.debug(this, - "Cannot create class data type for " + - recoveredClass.getClassNamespace().getName(true) + - " because it is diamond shaped and we don't yet handle that use case."); - } + Msg.debug(this, "Cannot create class data type for " + recoveredClass.getClassNamespace().getName(true) + + " because it is diamond shaped and we don't yet handle that use case."); return; } if (!recoveredClass.hasVftable()) { createSimpleClassStructure(recoveredClass, null); // return in this case because if there is no vftable for a class the script cannot - // identify any member functions so there is no need to process the rest of this method + // identify any member functions so there is no need to process the rest of this + // method return; } @@ -2914,7 +4090,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // then filled in later Map vfPointerDataTypes = createEmptyVfTableStructs(recoveredClass); - // create current class structure and add pointer to vftable, all parent member data + // create current class structure and add pointer to vftable, all parent member data // structures, and class member data structure Structure classStruct = createSimpleClassStructure(recoveredClass, vfPointerDataTypes); @@ -2922,11 +4098,11 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // name constructor and destructor functions and put into the class namespace addConstructorsToClassNamespace(recoveredClass, classStruct); addDestructorsToClassNamespace(recoveredClass, classStruct); - //TODO: + // TODO: // addNonThisDestructorsToClassNamespace(recoveredClass); // addVbaseDestructorsToClassNamespace(recoveredClass); // addVbtableToClassNamespace(recoveredClass); - //TODO: + // TODO: // // add secondary label on functions with inlined constructors or destructors // createInlinedConstructorComments(recoveredClass); // createInlinedDestructorComments(recoveredClass); @@ -2936,12 +4112,11 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { 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 + // because if done before the class structures are created // then empty classes will get auto-created in the wrong place // when the vfunctions are put in the class - fillInAndApplyVftableStructAndNameVfunctions(recoveredClass, vfPointerDataTypes, - classStruct); + fillInAndApplyVftableStructAndNameVfunctions(recoveredClass, vfPointerDataTypes, classStruct); } @@ -2952,13 +4127,12 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { CategoryPath classPath = recoveredClass.getClassPath(); - // get either existing structure if prog has a structure created by pdb or computed + // get either existing structure if prog has a structure created by pdb or computed // structure from decompiled construtor(s) info Structure classStructure; if (recoveredClass.hasExistingClassStructure()) { classStructure = recoveredClass.getExistingClassStructure(); - } - else { + } else { classStructure = recoveredClass.getComputedClassStructure(); } @@ -2967,11 +4141,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { structLen = addAlignment(classStructure.getLength()); } - Structure classStructureDataType = - new StructureDataType(classPath, className, structLen, dataTypeManager); + Structure classStructureDataType = new StructureDataType(classPath, className, structLen, dataTypeManager); // if no inheritance - add pointer to class vftable structure - if (nonInheritedGccClasses.contains(recoveredClass) && vfPointerDataTypes != null) { + if (nonInheritedClasses.contains(recoveredClass) && vfPointerDataTypes != null) { // the size was checked before calling this method so we know there is one and only // one for this simple case @@ -2980,27 +4153,23 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // simple case the offset for vftablePtr is 0 // if can fit or grow structure, add the vftablePtr to it - EditStructureUtils.addDataTypeToStructure(classStructureDataType, 0, - classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor); + EditStructureUtils.addDataTypeToStructure(classStructureDataType, 0, classVftablePointer, + CLASS_VTABLE_PTR_FIELD_EXT, monitor); } // if single inheritance or multi non-virtual (wouldn't have called this method if // it were virtually inherited) put parent struct and data into class struct else { - Map orderToParentMap = - classToParentOrderMap.get(recoveredClass); + Map orderToParentMap = classToParentOrderMap.get(recoveredClass); if (orderToParentMap == null || orderToParentMap.isEmpty()) { - throw new Exception( - "Vmi class " + recoveredClass.getClassNamespace().getName(true) + - " should have a parent in the classToParentOrderMap but doesn't"); + throw new Exception("Vmi class " + recoveredClass.getClassNamespace().getName(true) + + " should have a parent in the classToParentOrderMap but doesn't"); } - Map parentToOffsetMap = - classToParentOffsetMap.get(recoveredClass); + Map parentToOffsetMap = classToParentOffsetMap.get(recoveredClass); if (parentToOffsetMap.isEmpty()) { - throw new Exception( - "Vmi class " + recoveredClass.getClassNamespace().getName(true) + - " should have a parent in the classToParentOffsetMap but doesn't"); + throw new Exception("Vmi class " + recoveredClass.getClassNamespace().getName(true) + + " should have a parent in the classToParentOffsetMap but doesn't"); } int numParents = orderToParentMap.keySet().size(); @@ -3009,23 +4178,22 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { Long parentOffsetLong = parentToOffsetMap.get(parent); if (parentOffsetLong == null) { - throw new Exception( - "Can't get parent offset for " + parent.getClassNamespace().getName(true)); + throw new Exception("Can't get parent offset for " + parent.getClassNamespace().getName(true)); } int parentOffset = parentOffsetLong.intValue(); Structure baseClassStructure = getClassStructureFromDataTypeManager(parent); - // if we can't get the parent throw exception because it shouldn't get here if the + // if we can't get the parent throw exception because it shouldn't get here if the // parent doesn't exist if (baseClassStructure == null) { - throw new Exception(parent.getClassNamespace().getName(true) + - " : structure should exist but doesn't."); + throw new Exception( + parent.getClassNamespace().getName(true) + " : structure should exist but doesn't."); } - // if it fits at offset or is at the end and class structure can be grown, + // 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, parentOffset, - baseClassStructure, baseClassStructure.getName(), monitor); + EditStructureUtils.addDataTypeToStructure(classStructureDataType, parentOffset, baseClassStructure, + baseClassStructure.getName(), monitor); } } @@ -3034,52 +4202,67 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { int dataOffset = getDataOffset(recoveredClass, classStructureDataType); int dataLen = UNKNOWN; if (dataOffset != NONE) { - dataLen = EditStructureUtils.getNumberOfUndefinedsStartingAtOffset( - classStructureDataType, dataOffset, monitor); + dataLen = EditStructureUtils.getNumberOfUndefinedsStartingAtOffset(classStructureDataType, dataOffset, + monitor); } if (dataLen != UNKNOWN && dataLen > 0) { - Structure recoveredClassDataStruct = createClassMemberDataStructure(recoveredClass, - classStructureDataType, dataLen, dataOffset); + Structure recoveredClassDataStruct = createClassMemberDataStructure(recoveredClass, classStructureDataType, + dataLen, dataOffset); if (recoveredClassDataStruct != null) { - // if it fits at offset or is at the end and class structure can be grown, + // 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, dataOffset, - recoveredClassDataStruct, "data", monitor); + EditStructureUtils.addDataTypeToStructure(classStructureDataType, dataOffset, recoveredClassDataStruct, + "data", monitor); } } - //NEW: - classStructureDataType = - addClassVftables(classStructureDataType, recoveredClass, vfPointerDataTypes); + classStructureDataType = addClassVftables(classStructureDataType, recoveredClass, vfPointerDataTypes); - //NEW: unused at this point until something figures out how to create them and where to + // unused at this point until something figures out how to create them and where to // put them - classStructureDataType = - addVbtableToClassStructure(recoveredClass, classStructureDataType, true); + classStructureDataType = addVbtableToClassStructure(recoveredClass, classStructureDataType, true); - if (classStructureDataType.getNumComponents() == classStructureDataType - .getNumDefinedComponents()) { + if (classStructureDataType.getNumComponents() == classStructureDataType.getNumDefinedComponents()) { classStructureDataType.setPackingEnabled(true); } classStructureDataType.setDescription(createParentStringBuffer(recoveredClass).toString()); classStructureDataType = (Structure) dataTypeManager.addDataType(classStructureDataType, - DataTypeConflictHandler.DEFAULT_HANDLER); + DataTypeConflictHandler.DEFAULT_HANDLER); return classStructureDataType; } + private MemoryBlock getExternalBlock() { + return program.getMemory().getBlock("EXTERNAL"); + } + private boolean hasExternalBlock() { - MemoryBlock externalBlock = program.getMemory().getBlock(MemoryBlock.EXTERNAL_BLOCK_NAME); + + MemoryBlock externalBlock = getExternalBlock(); + if (externalBlock == null) { return false; } return true; } + private boolean inExternalBlock(Address address) { + + MemoryBlock externalBlock = getExternalBlock(); + if (externalBlock == null) { + return false; + } + if (externalBlock.contains(address)) { + return true; + } + return false; + + } + } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClass.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClass.java index 7192baad38..c9ddafe0b6 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClass.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClass.java @@ -606,7 +606,7 @@ public class RecoveredClass { DataTypeComponent component = computedClassStructure.getComponentAt(offset.intValue()); - if (!component.getDataType().equals(dataType)) { + if (component != null && !component.getDataType().equals(dataType)) { computedClassStructure.replaceAtOffset(offset.intValue(), dataType, dataType.getLength(), component.getFieldName(), component.getComment()); } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java index 15472874de..8f7795052f 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java @@ -191,7 +191,7 @@ public class RecoveredClassHelper { Iterator
referencesIterator = referencesToVftable.iterator(); while (referencesIterator.hasNext()) { Address vtableReference = referencesIterator.next(); - monitor.checkCanceled(); + monitor.checkCancelled(); vftableRefToVftableMap.put(vtableReference, vftableAddress); } } @@ -211,7 +211,7 @@ public class RecoveredClassHelper { Set
keySet = vftableRefToFunctionMapping.keySet(); Iterator
referencesIterator = keySet.iterator(); while (referencesIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address vtableReference = referencesIterator.next(); Function function = vftableRefToFunctionMapping.get(vtableReference); if (functionToVftableRefsMap.containsKey(function)) { @@ -247,7 +247,7 @@ public class RecoveredClassHelper { Iterator functionIterator = functions.iterator(); while (functionIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function function = functionIterator.next(); // if the map already contains a mapping for function and if // the associated class list doesn't contain the new class, then @@ -287,7 +287,7 @@ public class RecoveredClassHelper { List vftableSymbolList = new ArrayList(); while (vftableSymbols.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Symbol vftableSymbol = vftableSymbols.next(); if (vftableSymbol.getName().equals("vftable")) { vftableSymbolList.add(vftableSymbol); @@ -319,17 +319,46 @@ public class RecoveredClassHelper { SymbolIterator symbols = program.getSymbolTable().getSymbols(symbolName); while (symbols.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Symbol symbol = symbols.next(); if (symbol.getParentNamespace().getName().equals(namespaceName)) { Namespace namespace = symbol.getParentNamespace(); - if (namespace.getParentNamespace().getName().equals(parentNamespaceName)) { + Namespace parentNamespace = namespace.getParentNamespace(); + + // make this exact parent-namespace-name is global and is not in yet a further namespace + if (parentNamespace.getName().equals(parentNamespaceName) && parentNamespace.getParentNamespace().isGlobal()) { return symbol; } } } return null; } + + /** + * Method to return a list symbol in the given namespace which is in the given + * parent namespace or null if one is not found + * @param parentNamespaceName name of parent namespace + * @param namespaceName name of symbol namespace + * @param symbolName name of symbol + * @return Symbol with given name, namespace and parent namespace or null if doesn't exist + * @throws CancelledException if cancelled + */ + public List getSymbolsInNamespaces(String parentNamespaceName, String namespaceName) throws CancelledException { + + List symbolsInNamespace = new ArrayList(); + SymbolIterator symbols = program.getSymbolTable().getAllSymbols(false); + while (symbols.hasNext()) { + monitor.checkCancelled(); + Symbol symbol = symbols.next(); + if (symbol.getParentNamespace().getName().equals(namespaceName)) { + Namespace namespace = symbol.getParentNamespace(); + if (namespace.getParentNamespace().getName().equals(parentNamespaceName)) { + symbolsInNamespace.add(symbol); + } + } + } + return symbolsInNamespace; + } public Address getSingleAddressOfSymbolContainingBothStrings(String string1, String string2) throws CancelledException { @@ -340,7 +369,7 @@ public class RecoveredClassHelper { program.getSymbolTable().getSymbolIterator("*" + string1 + "*", true); while (symbols.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Symbol symbol = symbols.next(); Address symbolAddress = symbol.getAddress(); @@ -355,6 +384,27 @@ public class RecoveredClassHelper { } return null; } + + public List getSymbolsContainingBothStrings(String string1, String string2) + throws CancelledException { + + List symbolList = new ArrayList(); + + SymbolIterator symbols = + program.getSymbolTable().getSymbolIterator("*" + string1 + "*", true); + + while (symbols.hasNext()) { + monitor.checkCancelled(); + Symbol symbol = symbols.next(); + + if (symbol.getName().contains(string2)) { + symbolList.add(symbol); + } + } + + return symbolList; + + } /** * Method to create a map of calling address to called function for the given function. @@ -373,7 +423,7 @@ public class RecoveredClassHelper { function.getProgram().getListing().getInstructions(function.getBody(), true); while (instructions.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Instruction instruction = instructions.next(); if (instruction.getFlowType().isCall()) { @@ -427,7 +477,7 @@ public class RecoveredClassHelper { return allVfunctionsSet; } for (Address vftableAddress : vftableAddresses) { - monitor.checkCanceled(); + monitor.checkCancelled(); allVfunctionsSet.addAll(getVfunctions(vftableAddress)); } @@ -445,7 +495,7 @@ public class RecoveredClassHelper { for (Address vftableAddress : vftables) { - monitor.checkCanceled(); + monitor.checkCancelled(); List functionsThatReferenceVftable = geFunctionsThatReferenceAddress(vftableAddress); @@ -455,7 +505,7 @@ public class RecoveredClassHelper { } for (Function function : functionsThatReferenceVftable) { - monitor.checkCanceled(); + monitor.checkCancelled(); allFunctionsThatReferenceVftables.add(function); } @@ -477,7 +527,7 @@ public class RecoveredClassHelper { for (Address vftableAddress : vftables) { - monitor.checkCanceled(); + monitor.checkCancelled(); List possibleCDFunctions = geFunctionsThatReferenceAddress(vftableAddress); @@ -486,7 +536,7 @@ public class RecoveredClassHelper { } for (Function possibleCDFunction : possibleCDFunctions) { - monitor.checkCanceled(); + monitor.checkCancelled(); // possible cd's that are also virtual functions cannot be cds if (getAllVfunctions(vftables).contains(possibleCDFunction)) { @@ -561,7 +611,7 @@ public class RecoveredClassHelper { Iterator
iterator = vftableReferences.iterator(); while (iterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address vftableReference = iterator.next(); Address vftableAddress = vftableRefToVftableMap.get(vftableReference); RecoveredClass recoveredClass = vftableToClassMap.get(vftableAddress); @@ -595,7 +645,7 @@ public class RecoveredClassHelper { Iterator
vftableRefs = vftableReferenceList.iterator(); while (vftableRefs.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address vftableRef = vftableRefs.next(); Address vftableAddress = vftableRefToVftableMap.get(vftableRef); @@ -641,7 +691,7 @@ public class RecoveredClassHelper { Set
ancestorRefs = referenceToClassMapForFunction.keySet(); Iterator
ancestorRefIterator = ancestorRefs.iterator(); while (ancestorRefIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address ancestorRef = ancestorRefIterator.next(); RecoveredClass mappedClass = referenceToClassMapForFunction.get(ancestorRef); if (classHierarchy.contains(mappedClass)) { @@ -677,7 +727,7 @@ public class RecoveredClassHelper { Iterator
vftableRefIterator = vftableRefs.iterator(); while (vftableRefIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address vftableRef = vftableRefIterator.next(); Address vftableAddress = extendedFlatAPI.getSingleReferencedAddress(vftableRef); @@ -705,7 +755,7 @@ public class RecoveredClassHelper { } for (Address address : functionCallMap.keySet()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function calledFunction = functionCallMap.get(address); @@ -771,7 +821,7 @@ public class RecoveredClassHelper { RecoveredClass lastClass = null; Address lastVftableRef = null; while (vftableRefIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address vftableRef = vftableRefIterator.next(); RecoveredClass currentClass = map.get(vftableRef); @@ -794,7 +844,7 @@ public class RecoveredClassHelper { Instruction instruction = program.getListing().getInstructionAfter(ref1); int numApart = 0; while (instruction != null && !instruction.contains(ref2)) { - monitor.checkCanceled(); + monitor.checkCancelled(); numApart++; instruction = program.getListing().getInstructionAfter(instruction.getMaxAddress()); } @@ -835,7 +885,7 @@ public class RecoveredClassHelper { // try direct parents first Iterator parentsIterator = parentClasses.iterator(); while (parentsIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass parentClass = parentsIterator.next(); List constructorDestructorList = new ArrayList(parentClass.getConstructorList()); @@ -854,7 +904,7 @@ public class RecoveredClassHelper { ListIterator ancestorIterator = ancestorClasses.listIterator(1); while (ancestorIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass ancestorClass = ancestorIterator.next(); @@ -906,7 +956,7 @@ public class RecoveredClassHelper { Iterator iterator = storedPcodeOps.iterator(); // figure out if vftable is referenced while (iterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); OffsetPcodeOpPair offsetPcodeOpPair = iterator.next(); PcodeOp pcodeOp = offsetPcodeOpPair.getPcodeOp(); Varnode storedValue = pcodeOp.getInput(2); @@ -933,7 +983,7 @@ public class RecoveredClassHelper { while (iterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Reference reference = iterator.next(); Address vtableReference = reference.getFromAddress(); @@ -962,7 +1012,7 @@ public class RecoveredClassHelper { } Iterator functionClassesIterator = functionClasses.iterator(); while (functionClassesIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = functionClassesIterator.next(); if (recoveredClass.getInlinedDestructorList().contains(function)) { @@ -994,7 +1044,7 @@ public class RecoveredClassHelper { DataType[] originalTypes = new DataType[originalParameters.length]; SourceType[] originalSources = new SourceType[originalParameters.length]; for (int i = 0; i < originalParameters.length; i++) { - monitor.checkCanceled(); + monitor.checkCancelled(); originalTypes[i] = originalParameters[i].getDataType(); originalSources[i] = originalParameters[i].getSource(); } @@ -1019,7 +1069,7 @@ public class RecoveredClassHelper { // put back return and param data types that were temporarily removed Parameter[] parameters = function.getParameters(); for (int i = 0; i < parameters.length; i++) { - monitor.checkCanceled(); + monitor.checkCancelled(); if (parameters[i].getName().equals("this")) { continue; } @@ -1115,7 +1165,7 @@ public class RecoveredClassHelper { while (highVariableIterator.hasNext()) { HighVariable highVariable = highVariableIterator.next(); - monitor.checkCanceled(); + monitor.checkCancelled(); FillOutStructureCmd fillCmd = new FillOutStructureCmd(program, location, tool); @@ -1169,7 +1219,7 @@ public class RecoveredClassHelper { Iterator pcodeOps = highFunction.getPcodeOps(); while (pcodeOps.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); PcodeOp pcodeOp = pcodeOps.next(); if (pcodeOp.getOpcode() == PcodeOp.STORE) { @@ -1178,7 +1228,7 @@ public class RecoveredClassHelper { Varnode[] inputs = pcodeOp.getInputs(); for (Varnode input : inputs) { - monitor.checkCanceled(); + monitor.checkCancelled(); if (input.getHigh() != null) { highVars.add(input.getHigh()); } @@ -1208,7 +1258,7 @@ public class RecoveredClassHelper { int parameterCount = function.getParameterCount(); for (int i = 0; i < parameterCount; i++) { - monitor.checkCanceled(); + monitor.checkCancelled(); // if this call - temporarily put in global namespace to remove class structure // in order to get unbiased pcode store information @@ -1255,7 +1305,7 @@ public class RecoveredClassHelper { Iterator classIterator = recoveredClasses.iterator(); while (classIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = classIterator.next(); if (isClassAnAncestor(recoveredClass, possibleAncestor)) { @@ -1304,7 +1354,7 @@ public class RecoveredClassHelper { Iterator pcodeOpsIterator = pcodeOps.iterator(); while (pcodeOpsIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); OffsetPcodeOpPair offsetPcodeOpPair = pcodeOpsIterator.next(); PcodeOp pcodeOp = offsetPcodeOpPair.getPcodeOp(); Address pcodeOpAddress = pcodeOp.getSeqnum().getTarget(); @@ -1370,7 +1420,7 @@ public class RecoveredClassHelper { Iterator classIterator = recoveredClasses.iterator(); while (classIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = classIterator.next(); if (recoveredClass.hasVftable()) { classesWithVFunctions.add(recoveredClass); @@ -1405,7 +1455,7 @@ public class RecoveredClassHelper { Iterator parentIterator = parentClassList.iterator(); while (parentIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass parentClass = parentIterator.next(); if (parentClass.hasVftable()) { @@ -1437,7 +1487,7 @@ public class RecoveredClassHelper { Iterator ancestorIterator = classHierarchyList.iterator(); while (ancestorIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass parentClass = ancestorIterator.next(); if (parentClass.hasVftable()) { @@ -1464,7 +1514,7 @@ public class RecoveredClassHelper { Iterator hierarchyIterator = classHierarchy.iterator(); while (hierarchyIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass ancestorClass = hierarchyIterator.next(); // skip self @@ -1490,7 +1540,7 @@ public class RecoveredClassHelper { List classHierarchy = recoveredClass.getClassHierarchy(); Iterator recoveredClassIterator = classHierarchy.iterator(); while (recoveredClassIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass currentClass = recoveredClassIterator.next(); if (!currentClass.hasVftable()) { return true; @@ -1509,12 +1559,23 @@ public class RecoveredClassHelper { throws CancelledException { List allAncestorConstructors = new ArrayList(); + + List classHierarchy = recoveredClass.getClassHierarchy(); + if(classHierarchy == null) { + Msg.debug(this, recoveredClass.getName() + " has null class hierarchy list"); + return allAncestorConstructors; + } + + if(classHierarchy.isEmpty()) { + Msg.debug(this, recoveredClass.getName() + " has empty class hierarchy list"); + return allAncestorConstructors; + } ListIterator classHierarchyIterator = classHierarchy.listIterator(1); while (classHierarchyIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass currentClass = classHierarchyIterator.next(); List constructorList = @@ -1522,7 +1583,7 @@ public class RecoveredClassHelper { constructorList.addAll(currentClass.getInlinedConstructorList()); Iterator constructors = constructorList.iterator(); while (constructors.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function constructor = constructors.next(); if (!allAncestorConstructors.contains(constructor)) { allAncestorConstructors.add(constructor); @@ -1544,10 +1605,21 @@ public class RecoveredClassHelper { List allAncestorDestructors = new ArrayList(); List classHierarchy = recoveredClass.getClassHierarchy(); + + if(classHierarchy == null) { + Msg.debug(this, recoveredClass.getName() + " has null class hierarchy list"); + return allAncestorDestructors; + } + + if(classHierarchy.isEmpty()) { + Msg.debug(this, recoveredClass.getName() + " has empty class hierarchy list"); + return allAncestorDestructors; + } + ListIterator classHierarchyIterator = classHierarchy.listIterator(1); while (classHierarchyIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass parentClass = classHierarchyIterator.next(); List destructorList = @@ -1555,7 +1627,7 @@ public class RecoveredClassHelper { destructorList.addAll(parentClass.getInlinedDestructorList()); Iterator destructors = destructorList.iterator(); while (destructors.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function destructor = destructors.next(); if (!allAncestorDestructors.contains(destructor)) { allAncestorDestructors.add(destructor); @@ -1579,7 +1651,7 @@ public class RecoveredClassHelper { List childClasses = recoveredClass.getChildClasses(); Iterator childClassIterator = childClasses.iterator(); while (childClassIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass childClass = childClassIterator.next(); List constructorList = @@ -1587,7 +1659,7 @@ public class RecoveredClassHelper { constructorList.addAll(childClass.getInlinedConstructorList()); Iterator constructors = constructorList.iterator(); while (constructors.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function constructor = constructors.next(); if (!allDescendantConstructors.contains(constructor)) { allDescendantConstructors.add(constructor); @@ -1613,14 +1685,14 @@ public class RecoveredClassHelper { List childClasses = recoveredClass.getChildClasses(); Iterator childClassIterator = childClasses.iterator(); while (childClassIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass childClass = childClassIterator.next(); List destructorList = new ArrayList(childClass.getDestructorList()); destructorList.addAll(childClass.getInlinedDestructorList()); Iterator destructors = destructorList.iterator(); while (destructors.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function destructor = destructors.next(); if (!allDescendantDestructors.contains(destructor)) { allDescendantDestructors.add(destructor); @@ -1654,7 +1726,7 @@ public class RecoveredClassHelper { InstructionIterator instructions = function.getProgram().getListing().getInstructions(function.getBody(), true); while (instructions.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Instruction instruction = instructions.next(); if (instruction.getMinAddress().compareTo(minVftableReference) >= 0) { @@ -1703,7 +1775,7 @@ public class RecoveredClassHelper { InstructionIterator instructions = function.getProgram().getListing().getInstructions(function.getBody(), true); while (instructions.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Instruction instruction = instructions.next(); if (instruction.getMinAddress().compareTo(maxVftableReference) <= 0) { @@ -1802,7 +1874,7 @@ public class RecoveredClassHelper { Iterator constDestIterator = constDestFunctions.iterator(); while (constDestIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function constDestFunction = constDestIterator.next(); @@ -1860,7 +1932,7 @@ public class RecoveredClassHelper { // the addConstructor method processes the offsets and types for the initialized class data Iterator childConstructorIterator = constructorKeySet.iterator(); while (childConstructorIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function childConstructor = childConstructorIterator.next(); addConstructorToClass(recoveredClass, childConstructor); recoveredClass.removeIndeterminateConstructorOrDestructor(childConstructor); @@ -1872,7 +1944,7 @@ public class RecoveredClassHelper { // Do the same for the child/parent destructors Iterator childDestructorIterator = destructorKeySet.iterator(); while (childDestructorIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function childDestructor = childDestructorIterator.next(); addDestructorToClass(recoveredClass, childDestructor); recoveredClass.removeIndeterminateConstructorOrDestructor(childDestructor); @@ -2023,7 +2095,7 @@ public class RecoveredClassHelper { int order = 0; Iterator offsetIterator = offsetList.iterator(); while (offsetIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Integer offset = offsetIterator.next(); Address vftableAddress = classOffsetToVftableMap.get(offset); recoveredClass.addOrderToVftableMapping(order, vftableAddress); @@ -2041,7 +2113,7 @@ public class RecoveredClassHelper { Iterator recoveredClassIterator = recoveredClasses.iterator(); while (recoveredClassIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = recoveredClassIterator.next(); // create a mapping of the order of the vftable to the vftable address and save to class @@ -2064,7 +2136,7 @@ public class RecoveredClassHelper { Iterator
constructorIterator = referencesToConstructors.iterator(); while (constructorIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address constructorReference = constructorIterator.next(); RecoveredClass recoveredClass = referenceToClassMap.get(constructorReference); @@ -2109,7 +2181,7 @@ public class RecoveredClassHelper { List
referenceAddresses = new ArrayList
(referenceToClassMap.keySet()); Iterator
referenceIterator = referenceAddresses.iterator(); while (referenceIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address reference = referenceIterator.next(); Address vftableAddress = getVftableAddress(reference); if (vftableAddress != null) { @@ -2128,7 +2200,7 @@ public class RecoveredClassHelper { Iterator
refToVtablesIterator = referencesToVftables.iterator(); while (refToVtablesIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address refToVftable = refToVtablesIterator.next(); RecoveredClass referencedClass = referenceToClassMap.get(refToVftable); @@ -2170,7 +2242,7 @@ public class RecoveredClassHelper { List
referenceAddresses = new ArrayList
(referenceToClassMap.keySet()); Iterator
referenceIterator = referenceAddresses.iterator(); while (referenceIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address reference = referenceIterator.next(); Address vftableAddress = getVftableAddress(reference); if (vftableAddress != null) { @@ -2190,7 +2262,7 @@ public class RecoveredClassHelper { Iterator
refToVtablesIterator = referencesToVftables.iterator(); while (refToVtablesIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address refToVftable = refToVtablesIterator.next(); RecoveredClass referencedClass = referenceToClassMap.get(refToVftable); @@ -2259,7 +2331,7 @@ public class RecoveredClassHelper { .getListing() .getInstructions(callingFunction.getBody(), true); while (instructions.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Instruction instruction = instructions.next(); if (instruction.getFlowType().isCall()) { @@ -2289,7 +2361,7 @@ public class RecoveredClassHelper { .getListing() .getInstructions(callingFunction.getBody(), true); while (instructions.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Instruction instruction = instructions.next(); if (instruction.getFlowType().isCall()) { @@ -2321,7 +2393,7 @@ public class RecoveredClassHelper { int total = 0; Iterator classIterator = recoveredClasses.iterator(); while (classIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = classIterator.next(); List constructorList = recoveredClass.getConstructorList(); total += constructorList.size(); @@ -2341,7 +2413,7 @@ public class RecoveredClassHelper { int total = 0; Iterator classIterator = recoveredClasses.iterator(); while (classIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = classIterator.next(); int numDestructors = recoveredClass.getDestructorList().size(); @@ -2362,7 +2434,7 @@ public class RecoveredClassHelper { int total = 0; Iterator classIterator = recoveredClasses.iterator(); while (classIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = classIterator.next(); int numInlinedDestructors = recoveredClass.getInlinedDestructorList().size(); @@ -2383,7 +2455,7 @@ public class RecoveredClassHelper { int total = 0; Iterator classIterator = recoveredClasses.iterator(); while (classIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = classIterator.next(); List deletingDestructors = recoveredClass.getDeletingDestructors(); @@ -2404,7 +2476,7 @@ public class RecoveredClassHelper { int total = 0; Iterator classIterator = recoveredClasses.iterator(); while (classIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = classIterator.next(); List cloneFunctions = recoveredClass.getCloneFunctions(); total += cloneFunctions.size(); @@ -2424,7 +2496,7 @@ public class RecoveredClassHelper { int total = 0; Iterator classIterator = recoveredClasses.iterator(); while (classIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = classIterator.next(); Function cloneFunction = recoveredClass.getVBaseDestructor(); @@ -2447,7 +2519,7 @@ public class RecoveredClassHelper { int total = 0; Iterator classIterator = recoveredClasses.iterator(); while (classIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = classIterator.next(); List vfunctionList = recoveredClass.getAllVirtualFunctions(); @@ -2475,7 +2547,7 @@ public class RecoveredClassHelper { List remainingIndeterminates = new ArrayList(); Iterator classIterator = recoveredClasses.iterator(); while (classIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = classIterator.next(); List indeterminateConstructorOrDestructorList = @@ -2503,7 +2575,7 @@ public class RecoveredClassHelper { Iterator
destructorIterator = referencesToDestructors.iterator(); while (destructorIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address destructorReference = destructorIterator.next(); RecoveredClass recoveredClass = referenceToClassMap.get(destructorReference); @@ -2537,13 +2609,13 @@ public class RecoveredClassHelper { Iterator recoveredClassIterator = recoveredClasses.iterator(); while (recoveredClassIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = recoveredClassIterator.next(); List indeterminateFunctions = recoveredClass.getIndeterminateList(); Iterator functionIterator = indeterminateFunctions.iterator(); while (functionIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function function = functionIterator.next(); Namespace namespace = function.getParentNamespace(); @@ -2565,6 +2637,8 @@ public class RecoveredClassHelper { } } + + /** * Method to determine if a class's identified vbase_destructor is valid or not @@ -2611,7 +2685,7 @@ public class RecoveredClassHelper { List childClasses = recoveredClass.getChildClasses(); Iterator childIterator = childClasses.iterator(); while (childIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass childClass = childIterator.next(); if (childClass.getDestructorList().size() == 1 && childClass.getVBaseDestructor() != null) { @@ -2673,7 +2747,7 @@ public class RecoveredClassHelper { Iterator vftableSymbolsIterator = vftableSymbolList.iterator(); while (vftableSymbolsIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Symbol vftableSymbol = vftableSymbolsIterator.next(); Address vftableAddress = vftableSymbol.getAddress(); @@ -2745,13 +2819,77 @@ public class RecoveredClassHelper { } // end of looping over vfTables return recoveredClasses; } + + //TODO: rework above method to call this so it works with both that and other calls + protected void updateClassWithVftable(RecoveredClass recoveredClass, Symbol vftableSymbol, + boolean allowNullFunctionPtrs, boolean allowDefaultRefsInMiddle) throws Exception { + // get only the functions from the ones that are not already processed + // structures + // return null if not an unprocessed table + + Address vftableAddress = vftableSymbol.getAddress(); + Namespace vftableNamespace = vftableSymbol.getParentNamespace(); + + List virtualFunctions = getFunctionsFromVftable(vftableAddress, vftableSymbol, allowNullFunctionPtrs, + allowDefaultRefsInMiddle); + + // the vftable has already been processed - skip it + if (virtualFunctions == null) { + return; + } + + // Check to see if already have an existing RecoveredClass object for the + // class associated with the current vftable. + recoveredClass = getClass(vftableNamespace); + + if (recoveredClass == null) { + // Create a RecoveredClass object for the current class + recoveredClass = createNewClass(vftableNamespace, true); + recoveredClass.addVftableAddress(vftableAddress); + recoveredClass.addVftableVfunctionsMapping(vftableAddress, virtualFunctions); + + // add it to the running list of RecoveredClass objects + // recoveredClasses.add(recoveredClass); + } else { + recoveredClass.addVftableAddress(vftableAddress); + recoveredClass.addVftableVfunctionsMapping(vftableAddress, virtualFunctions); +// if (!recoveredClasses.contains(recoveredClass)) { +// recoveredClasses.add(recoveredClass); +// } + + } + + // add it to the vftableAddress to Class map + updateVftableToClassMap(vftableAddress, recoveredClass); + + List
referencesToVftable = getReferencesToVftable(vftableAddress); + addReferenceToVtableMapping(referencesToVftable, vftableAddress); + + Map vftableReferenceToFunctionMapping = createVftableReferenceToFunctionMapping( + referencesToVftable); + + // vftableReferenceToFunctionMapping + List possibleConstructorDestructorsForThisClass = findPossibleConstructorDestructors( + vftableReferenceToFunctionMapping); + + addFunctionsToClassMapping(possibleConstructorDestructorsForThisClass, recoveredClass); + + // add the vftable reference to function mapping to the global list + addFunctionToVftableReferencesMapping(vftableReferenceToFunctionMapping); + + // add the possible constructor/destructor list to the class + recoveredClass.addConstructorDestructorList(possibleConstructorDestructorsForThisClass); + recoveredClass.addIndeterminateConstructorOrDestructorList(possibleConstructorDestructorsForThisClass); + + // } // end of looping over vfTables + } public void promoteClassNamespaces(List recoveredClasses) throws CancelledException { Iterator classIterator = recoveredClasses.iterator(); while (classIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = classIterator.next(); Namespace classNamespace = recoveredClass.getClassNamespace(); @@ -2763,7 +2901,7 @@ public class RecoveredClassHelper { while (!namespace.isGlobal()) { - monitor.checkCanceled(); + monitor.checkCancelled(); SymbolType namespaceType = namespace.getSymbol().getSymbolType(); // if it is a namespace but not a class and it is in our namespace map (which makes // it a valid class) we need to promote it to a class namespace @@ -2834,7 +2972,7 @@ public class RecoveredClassHelper { Map vftableRefToFunctionMapping = new HashMap(); Iterator
referencesIterator = referencesToVftable.iterator(); while (referencesIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address vftableReference = referencesIterator.next(); Function functionContaining = extendedFlatAPI.getFunctionContaining(vftableReference); if (functionContaining != null) { @@ -2858,7 +2996,7 @@ public class RecoveredClassHelper { Set
keySet = vftableReferenceToFunctionMapping.keySet(); Iterator
referencesIterator = keySet.iterator(); while (referencesIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address vtableReference = referencesIterator.next(); Function function = vftableReferenceToFunctionMapping.get(vtableReference); if (!cdFunctions.contains(function)) { @@ -2918,7 +3056,7 @@ public class RecoveredClassHelper { int numPointers = vftableData.getNumComponents(); for (int i = 0; i < numPointers; ++i) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address functionPointerAddress = vftableData.getComponent(i).getAddress(); if (allowNullFunctionPtrs && extendedFlatAPI.isNullPointer(functionPointerAddress)) { @@ -3011,7 +3149,7 @@ public class RecoveredClassHelper { AddressSetView executeSet = program.getMemory().getExecuteSet(); AddressRangeIterator addressRanges = executeSet.getAddressRanges(); while (addressRanges.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); AddressRange addressRange = addressRanges.next(); searchSet.add(addressRange.getMinAddress(), addressRange.getMaxAddress()); } @@ -3023,7 +3161,7 @@ public class RecoveredClassHelper { Iterator vftableSymbolIterator = vftableSymbols.iterator(); while (vftableSymbolIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Symbol vftableSymbol = vftableSymbolIterator.next(); Address vftableAddress = vftableSymbol.getAddress(); vftableAddresses.add(vftableAddress); @@ -3041,7 +3179,7 @@ public class RecoveredClassHelper { // check existing refs to see if in instruction but not in function Iterator
vftableAddressIterator = vftableAddresses.iterator(); while (vftableAddressIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address vftableAddress = vftableAddressIterator.next(); @@ -3049,7 +3187,7 @@ public class RecoveredClassHelper { program.getReferenceManager().getReferencesTo(vftableAddress); while (referencesIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Reference reference = referencesIterator.next(); Address vftableReference = reference.getFromAddress(); @@ -3167,7 +3305,7 @@ public class RecoveredClassHelper { Set ancestors = parentToBaseTypeMap.keySet(); Iterator ancestorIterator = ancestors.iterator(); while (ancestorIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass ancestor = ancestorIterator.next(); if (directParents.contains(ancestor)) { @@ -3209,7 +3347,7 @@ public class RecoveredClassHelper { Iterator parentIterator = parentClasses.listIterator(1); while (parentIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass parentClass = parentIterator.next(); if (getClassStructureFromDataTypeManager(parentClass) == null) { @@ -3256,7 +3394,7 @@ public class RecoveredClassHelper { Iterator constructorsIterator = constructorList.iterator(); while (constructorsIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function constructorFunction = constructorsIterator.next(); if (nameVfunctions) { @@ -3343,7 +3481,7 @@ public class RecoveredClassHelper { List destructorList = recoveredClass.getDestructorList(); Iterator destructorIterator = destructorList.iterator(); while (destructorIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function destructorFunction = destructorIterator.next(); String destructorName = "~" + className; @@ -3370,7 +3508,7 @@ public class RecoveredClassHelper { List nonThisDestructorList = recoveredClass.getNonThisDestructors(); Iterator destructorIterator = nonThisDestructorList.iterator(); while (destructorIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function destructorFunction = destructorIterator.next(); String destructorName = "~" + className; @@ -3461,7 +3599,7 @@ public class RecoveredClassHelper { else { Iterator iterator = symbolsByNameAtAddress.iterator(); while (iterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Symbol sameNameSymbol = iterator.next(); sameNameSymbol.setNamespace(namespace); } @@ -3571,7 +3709,7 @@ public class RecoveredClassHelper { else { Iterator iterator = symbolsByNameAtAddress.iterator(); while (iterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Symbol sameNameSymbol = iterator.next(); sameNameSymbol.setNamespace(namespace); } @@ -3699,7 +3837,7 @@ public class RecoveredClassHelper { // add all the new bad dts to the list of bad ones Iterator badStructuresIterator = badStructureDataTypes.iterator(); while (badStructuresIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Structure structure = badStructuresIterator.next(); if (!badFIDStructures.contains(structure)) { badFIDStructures.add(structure); @@ -3726,11 +3864,11 @@ public class RecoveredClassHelper { Set callingFunctions = function.getCallingFunctions(monitor); while (callingFunctions != null && !callingFunctions.isEmpty()) { - monitor.checkCanceled(); + monitor.checkCancelled(); List moreCallingFunctions = new ArrayList(); Iterator callingFunctionsIterator = callingFunctions.iterator(); while (callingFunctionsIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function callingFunction = callingFunctionsIterator.next(); if (!allFunctionsToFix.contains(callingFunction)) { allFunctionsToFix.add(callingFunction); @@ -3743,7 +3881,7 @@ public class RecoveredClassHelper { Iterator functionsToFixIterator = allFunctionsToFix.iterator(); while (functionsToFixIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function functionToFix = functionsToFixIterator.next(); if (!functionToFix.isThunk()) { @@ -3771,7 +3909,7 @@ public class RecoveredClassHelper { int parameterCount = function.getParameterCount(); for (int i = 0; i < parameterCount; i++) { - monitor.checkCanceled(); + monitor.checkCancelled(); DataType dataType = function.getParameter(i).getDataType(); if (!dataType.getName().equals(namespace.getName()) && extendedFlatAPI.isPointerToEmptyStructure(dataType)) { @@ -3802,7 +3940,7 @@ public class RecoveredClassHelper { int parameterCount = function.getParameterCount(); for (int i = 0; i < parameterCount; i++) { - monitor.checkCanceled(); + monitor.checkCancelled(); DataType paramDataType = function.getParameter(i).getDataType(); Structure baseDataType = extendedFlatAPI.getBaseStructureDataType(paramDataType); if (baseDataType != null && badStructureDataTypes.contains(baseDataType)) { @@ -3887,7 +4025,7 @@ public class RecoveredClassHelper { SymbolIterator it = symbolTable.getSymbolsAsIterator(address); for (Symbol symbol : it) { - monitor.checkCanceled(); + monitor.checkCancelled(); String simpleSymbolName = extendedFlatAPI.removeTemplate(symbol.getName()); simpleSymbolName = removeSingleQuotes(simpleSymbolName); @@ -3943,7 +4081,7 @@ public class RecoveredClassHelper { Symbol[] symbols = symbolTable.getSymbols(address); for (Symbol symbol : symbols) { - monitor.checkCanceled(); + monitor.checkCancelled(); Namespace namespace = symbol.getParentNamespace(); if (namespace.isGlobal() && symbol.getName().equals(name)) { @@ -3984,7 +4122,7 @@ public class RecoveredClassHelper { constructor.getProgram().getListing().getInstructions(constructor.getBody(), true); while (instructions.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Instruction instruction = instructions.next(); Address instructionAddress = instruction.getAddress(); if (instructionAddress.compareTo(vftableReference) >= 0) { @@ -4024,7 +4162,7 @@ public class RecoveredClassHelper { Iterator recoveredClassIterator = recoveredClasses.iterator(); while (recoveredClassIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = recoveredClassIterator.next(); @@ -4036,7 +4174,7 @@ public class RecoveredClassHelper { } for (Function vfunction : allVirtualFunctions) { - monitor.checkCanceled(); + monitor.checkCancelled(); if (!hasNCalls(vfunction, 2)) { continue; @@ -4080,7 +4218,7 @@ public class RecoveredClassHelper { int numCalls = 0; while (instructions.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Instruction instruction = instructions.next(); if (instruction.getFlowType().isCall()) { numCalls++; @@ -4104,7 +4242,7 @@ public class RecoveredClassHelper { Iterator badNamespaceIterator = badFIDNamespaces.iterator(); while (badNamespaceIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Namespace badNamespace = badNamespaceIterator.next(); // global namespace shouldn't be on list but check anyway @@ -4135,7 +4273,7 @@ public class RecoveredClassHelper { namespace.getSymbol().delete(); while (parentNamespace != null && !extendedFlatAPI.hasSymbolsInNamespace(parentNamespace)) { - monitor.checkCanceled(); + monitor.checkCancelled(); namespace = parentNamespace; parentNamespace = parentNamespace.getParentNamespace(); @@ -4152,7 +4290,7 @@ public class RecoveredClassHelper { Iterator badStructureIterator = badFIDStructures.iterator(); while (badStructureIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); // if not used by anything remove it Structure badStructure = badStructureIterator.next(); @@ -4188,7 +4326,7 @@ public class RecoveredClassHelper { Category parentCategory = classCategory.getParent(); boolean tryToRemove = true; while (parentCategory != null && tryToRemove) { - monitor.checkCanceled(); + monitor.checkCancelled(); tryToRemove = parentCategory.removeEmptyCategory(classCategory.getName(), monitor); classCategory = parentCategory; @@ -4222,7 +4360,7 @@ public class RecoveredClassHelper { for (int index = 0; index < orderToVftableMap.size(); index++) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address vftableAddress = orderToVftableMap.get(index); @@ -4286,7 +4424,7 @@ public class RecoveredClassHelper { int numComponents = computedClassDataStructure.getNumDefinedComponents(); for (int i = 1; i < numComponents; i++) { - monitor.checkCanceled(); + monitor.checkCancelled(); DataTypeComponent component = computedClassDataStructure.getComponent(i); int offset = component.getOffset(); classStruct.replaceAtOffset(offset, component.getDataType(), @@ -4334,11 +4472,15 @@ public class RecoveredClassHelper { Iterator
vftableAddressIterator = vftableAddresses.iterator(); while (vftableAddressIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address vftableAddress = vftableAddressIterator.next(); PointerDataType vftablePointerDataType = (PointerDataType) vftableToStructureMap.get(vftableAddress); + + if(vftablePointerDataType == null) { + Msg.debug(this, "vftablePointerDataType is null for vftableAddress: " + vftableAddress); + } DataType vftableDataType = vftablePointerDataType.getDataType(); @@ -4359,7 +4501,7 @@ public class RecoveredClassHelper { while (vfIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function vfunction = vfIterator.next(); if (vfunction == null) { @@ -4554,7 +4696,7 @@ public class RecoveredClassHelper { String vfunctionSuffix = getForClassSuffix(vftableStructureName); while (vfIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function vfunction = vfIterator.next(); // create a one-up number for the next virtual function @@ -4635,7 +4777,7 @@ public class RecoveredClassHelper { Symbol[] symbols = symbolTable.getSymbols(address); for (Symbol symbol : symbols) { - monitor.checkCanceled(); + monitor.checkCancelled(); if (symbol.getName().contains("deleting_destructor") && symbol.getParentNamespace().equals(namespace)) { @@ -4735,7 +4877,7 @@ public class RecoveredClassHelper { // } while (classHierarchyIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass currentClass = classHierarchyIterator.next(); @@ -4797,7 +4939,7 @@ public class RecoveredClassHelper { Iterator inlinedConstructorsIterator = inlinedConstructorList.iterator(); while (inlinedConstructorsIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function inlinedFunction = inlinedConstructorsIterator.next(); List
listOfClassRefsInFunction = @@ -4836,7 +4978,7 @@ public class RecoveredClassHelper { List inlinedDestructorList = recoveredClass.getInlinedDestructorList(); Iterator inlinedDestructorIterator = inlinedDestructorList.iterator(); while (inlinedDestructorIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function destructorFunction = inlinedDestructorIterator.next(); Address classVftableRef = getFirstClassVftableReference(recoveredClass, destructorFunction); @@ -4865,7 +5007,7 @@ public class RecoveredClassHelper { Iterator functionsContainingInlineIterator = functionsContainingInlineList.iterator(); while (functionsContainingInlineIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function functionContainingInline = functionsContainingInlineIterator.next(); Address classVftableRef = @@ -4898,7 +5040,7 @@ public class RecoveredClassHelper { List unknownIfConstructorOrDestructorLIst = recoveredClass.getIndeterminateList(); Iterator unknownsIterator = unknownIfConstructorOrDestructorLIst.iterator(); while (unknownsIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function indeterminateFunction = unknownsIterator.next(); if (nameVfunctions) { @@ -4995,12 +5137,12 @@ public class RecoveredClassHelper { Set twoCallCommonFunctions = new HashSet(); for (RecoveredClass recoveredClass : recoveredClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); List virtualFunctions = recoveredClass.getAllVirtualFunctions(); List cdFunctions = recoveredClass.getConstructorOrDestructorFunctions(); for (Function cdFunction : cdFunctions) { - monitor.checkCanceled(); + monitor.checkCancelled(); // if it isn't on both lists continue if (!virtualFunctions.contains(cdFunction)) { @@ -5026,14 +5168,14 @@ public class RecoveredClassHelper { Set twoCallCommonFunctions = new HashSet(); for (Address vftableAddress : vftableAddresses) { - monitor.checkCanceled(); + monitor.checkCancelled(); List possibleCDFunctions = geFunctionsThatReferenceAddress(vftableAddress); List virtualFunctions = getVfunctions(vftableAddress); for (Function cdFunction : possibleCDFunctions) { - monitor.checkCanceled(); + monitor.checkCancelled(); // if it isn't on both lists continue if (!virtualFunctions.contains(cdFunction)) { @@ -5068,7 +5210,7 @@ public class RecoveredClassHelper { while (iterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Reference reference = iterator.next(); Address refFromAddress = reference.getFromAddress(); @@ -5107,7 +5249,7 @@ public class RecoveredClassHelper { int numPointers = vftableData.getNumComponents(); for (int i = 0; i < numPointers; ++i) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address functionPointerAddress = vftableData.getComponent(i).getAddress(); @@ -5155,7 +5297,7 @@ public class RecoveredClassHelper { Function mostCommonOpDelete = null; for (Function function : twoCallCommonFunctions) { - monitor.checkCanceled(); + monitor.checkCancelled(); // get first called function - get the thunked one if it is a thunk Function firstCalledFunction = @@ -5227,7 +5369,7 @@ public class RecoveredClassHelper { Function mostCommonOpNew = null; for (Function function : twoCallCommonFunctions) { - monitor.checkCanceled(); + monitor.checkCancelled(); // get first called function - not the thunked // need the actual called function for the operator new test @@ -5286,7 +5428,7 @@ public class RecoveredClassHelper { } for (Address address : functionThunkAddresses) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function thunkFunction = functionManager.getFunctionAt(address); thunkFunctions.add(thunkFunction); @@ -5310,12 +5452,12 @@ public class RecoveredClassHelper { Iterator recoveredClassIterator = recoveredClasses.iterator(); while (recoveredClassIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = recoveredClassIterator.next(); List indeterminateFunctions = recoveredClass.getIndeterminateList(); Iterator indeterminateIterator = indeterminateFunctions.iterator(); while (indeterminateIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function indeterminateFunction = indeterminateIterator.next(); List
vftableReferenceList = getVftableReferences(indeterminateFunction); @@ -5358,7 +5500,7 @@ public class RecoveredClassHelper { for (DataTypeComponent dataTypeComponent : structureToAdd.getDefinedComponents()) { - monitor.checkCanceled(); + monitor.checkCancelled(); // only copy the components up to the given total dataLength to copy if ((dataTypeComponent.getOffset() + dataTypeComponent.getLength()) > dataLength) { @@ -5402,7 +5544,7 @@ public class RecoveredClassHelper { for (DataTypeComponent dataTypeComponent : definedComponents) { // if run into a virtual parent class structure, return its offset - monitor.checkCanceled(); + monitor.checkCancelled(); if (isVirtualParentClassStructure(recoveredClass, dataTypeComponent.getDataType())) { return dataTypeComponent.getOffset(); } @@ -5439,7 +5581,7 @@ public class RecoveredClassHelper { for (DataTypeComponent dataTypeComponent : definedComponents) { - monitor.checkCanceled(); + monitor.checkCancelled(); definedOffsets.add(dataTypeComponent.getOffset()); } Collections.sort(definedOffsets); @@ -5452,7 +5594,7 @@ public class RecoveredClassHelper { // loop to find the first defined offset after the segment of undefineds for (Integer currentOffset : definedOffsets) { - monitor.checkCanceled(); + monitor.checkCancelled(); DataTypeComponent dataTypeComponent = structure.getComponentAt(currentOffset); @@ -5502,7 +5644,7 @@ public class RecoveredClassHelper { Iterator parentClassIterator = parentClasses.iterator(); while (parentClassIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass parentClass = parentClassIterator.next(); if (parentClass.getName().equals(parentClassName)) { Boolean isVirtualParent = parentToBaseTypeMap.get(parentClass); @@ -5537,7 +5679,7 @@ public class RecoveredClassHelper { for (RecoveredClass parentClass : parentClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); Boolean isVirtualParent = parentToBaseTypeMap.get(parentClass); if (isVirtualParent) { @@ -5568,7 +5710,7 @@ public class RecoveredClassHelper { Iterator parentClassIterator = parentClasses.iterator(); while (parentClassIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass parentClass = parentClassIterator.next(); Boolean isVirtualParent = parentToBaseTypeMap.get(parentClass); @@ -5607,13 +5749,13 @@ public class RecoveredClassHelper { Iterator recoveredClassIterator = recoveredClasses.iterator(); while (recoveredClassIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = recoveredClassIterator.next(); List indeterminateFunctions = recoveredClass.getIndeterminateList(); Iterator indeterminateIterator = indeterminateFunctions.iterator(); while (indeterminateIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function indeterminateFunction = indeterminateIterator.next(); DataType returnDataType = @@ -5681,12 +5823,12 @@ public class RecoveredClassHelper { Iterator recoveredClassIterator = recoveredClasses.iterator(); while (recoveredClassIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = recoveredClassIterator.next(); List constructorList = recoveredClass.getConstructorList(); Iterator constructorIterator = constructorList.iterator(); while (constructorIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function constructor = constructorIterator.next(); // get the references to the vftable(s) that are referenced in this function @@ -5745,7 +5887,7 @@ public class RecoveredClassHelper { InstructionIterator instructionsIterator = listing.getInstructions(functionAddressSet, true); while (instructionsIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Instruction instruction = instructionsIterator.next(); if (!instruction.isFallthrough() && (!instruction.getFlowType().isCall())) { instructionAddress = instruction.getAddress(); @@ -5806,7 +5948,7 @@ public class RecoveredClassHelper { while (highVariableIterator.hasNext()) { HighVariable highVariable = highVariableIterator.next(); - monitor.checkCanceled(); + monitor.checkCancelled(); FillOutStructureCmd fillCmd = new FillOutStructureCmd(program, location, tool); fillCmd.processStructure(highVariable, function); @@ -5846,7 +5988,7 @@ public class RecoveredClassHelper { Iterator recoveredClassIterator = recoveredClasses.iterator(); while (recoveredClassIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = recoveredClassIterator.next(); List inlineFunctionsList = @@ -5854,7 +5996,7 @@ public class RecoveredClassHelper { Iterator inlineIterator = inlineFunctionsList.iterator(); while (inlineIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function inlineFunction = inlineIterator.next(); @@ -5875,7 +6017,7 @@ public class RecoveredClassHelper { Iterator
functionReferenceIterator = referencesToFunctions.iterator(); while (functionReferenceIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address functionReference = functionReferenceIterator.next(); Function function = extendedFlatAPI.getReferencedFunction(functionReference, true); @@ -6031,13 +6173,13 @@ public class RecoveredClassHelper { Iterator classIterator = recoveredClasses.iterator(); while (classIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = classIterator.next(); List indeterminateList = recoveredClass.getIndeterminateList(); Iterator indeterminateIterator = indeterminateList.iterator(); while (indeterminateIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function indeterminateFunction = indeterminateIterator.next(); // first try identifying useing known constructors and destructors @@ -6164,7 +6306,7 @@ public class RecoveredClassHelper { ReferenceIterator referenceIterator = program.getReferenceManager().getReferencesTo(atexitFunction.getEntryPoint()); while (referenceIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Reference ref = referenceIterator.next(); Address fromAddress = ref.getFromAddress(); @@ -6189,7 +6331,7 @@ public class RecoveredClassHelper { Iterator pcodeOps = highFunction.getPcodeOps(fromAddress); while (pcodeOps.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); PcodeOpAST pcodeOp = pcodeOps.next(); int opcode = pcodeOp.getOpcode(); if (opcode == PcodeOp.CALL) { @@ -6269,7 +6411,7 @@ public class RecoveredClassHelper { } Iterator
vftableReferencesIterator = vftableReferences.iterator(); while (vftableReferencesIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address vftableReference = vftableReferencesIterator.next(); Address vftableAddress = getVftableAddress(vftableReference); if (vftableAddress == null) { @@ -6301,7 +6443,7 @@ public class RecoveredClassHelper { Iterator functionIterator = classConstructorOrDestructorFunctions.iterator(); while (functionIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function function = functionIterator.next(); @@ -6335,7 +6477,7 @@ public class RecoveredClassHelper { Iterator recoveredClassIterator = recoveredClasses.iterator(); while (recoveredClassIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = recoveredClassIterator.next(); List parentsToProcess = recoveredClass.getParentList(); @@ -6348,7 +6490,7 @@ public class RecoveredClassHelper { while (parentsToProcessIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass parentToProcess = parentsToProcessIterator.next(); processConstructorsAndDestructorsUsingParent(recoveredClass, parentToProcess); @@ -6375,7 +6517,7 @@ public class RecoveredClassHelper { Iterator recoveredClassIterator = recoveredClasses.iterator(); while (recoveredClassIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = recoveredClassIterator.next(); List indeterminateList = recoveredClass.getIndeterminateList(); @@ -6389,7 +6531,7 @@ public class RecoveredClassHelper { Iterator indeterminateIterator = indeterminateList.iterator(); while (indeterminateIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function indeterminateFunction = indeterminateIterator.next(); @@ -6449,7 +6591,7 @@ public class RecoveredClassHelper { Iterator recoveredClassIterator = recoveredClasses.iterator(); while (recoveredClassIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = recoveredClassIterator.next(); List indeterminateList = @@ -6464,7 +6606,7 @@ public class RecoveredClassHelper { Iterator indeterminateIterator = indeterminateList.iterator(); while (indeterminateIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function indeterminateFunction = indeterminateIterator.next(); // get the addresses in the function that refer to classes either by @@ -6542,14 +6684,14 @@ public class RecoveredClassHelper { Iterator recoveredClassIterator = recoveredClasses.iterator(); while (recoveredClassIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = recoveredClassIterator.next(); List indeterminateList = recoveredClass.getIndeterminateList(); Iterator indeterminateIterator = indeterminateList.iterator(); while (indeterminateIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function indeterminateFunction = indeterminateIterator.next(); if (atexitCalledFunctions.contains(indeterminateFunction)) { recoveredClass.addNonThisDestructor(indeterminateFunction); @@ -6561,7 +6703,7 @@ public class RecoveredClassHelper { Iterator indeterminateInlineIterator = indeterminateInlineList.iterator(); while (indeterminateInlineIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function indeterminateFunction = indeterminateInlineIterator.next(); if (atexitCalledFunctions.contains(indeterminateFunction)) { addInlinedDestructorToClass(recoveredClass, indeterminateFunction); @@ -6606,7 +6748,7 @@ public class RecoveredClassHelper { // iterate over all class virtual functions to find the ones that are deleting destructors for (RecoveredClass recoveredClass : recoveredClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); List vfunctions = recoveredClass.getAllVirtualFunctions(); @@ -6615,7 +6757,7 @@ public class RecoveredClassHelper { } for (Function vfunction : vfunctions) { - monitor.checkCanceled(); + monitor.checkCancelled(); // get the map of addresses in vfunction to the corresponding functions called // from those addresses @@ -6719,7 +6861,7 @@ public class RecoveredClassHelper { operatorDeletes = new ArrayList(operatorDeletesSet); for (Function operatorDeleteFunction : operatorDeletes) { - monitor.checkCanceled(); + monitor.checkCancelled(); bookmarkAddress(operatorDeleteFunction.getEntryPoint(), "operator_delete function", "operator_delete identification"); @@ -6738,7 +6880,7 @@ public class RecoveredClassHelper { operatorNews = new ArrayList(operatorNewsSet); for (Function operatorNewFunction : operatorNews) { - monitor.checkCanceled(); + monitor.checkCancelled(); bookmarkAddress(operatorNewFunction.getEntryPoint(), "operator_new function", "operator_new identification"); @@ -6768,7 +6910,7 @@ public class RecoveredClassHelper { Collections.sort(callingAddresses); for (Address callingAddress : callingAddresses) { - monitor.checkCanceled(); + monitor.checkCancelled(); // skip if the function call is after the operator delete if (callingAddress.getOffset() > operatorDeleteCallingAddress.getOffset()) { @@ -6787,10 +6929,10 @@ public class RecoveredClassHelper { Function calledFunction = addressToFunctionCallMap.get(callingAddress); if (calledFunction != null) { if (calledFunction.isThunk()) { - // TODO: should all thunks and real function be returned? - calledFunction.getThunkedFunction(true); + calledFunction = calledFunction.getThunkedFunction(true); } possibleCalledDestructorSet.add(calledFunction); + } } List possibleCalledDestructors = @@ -6809,7 +6951,7 @@ public class RecoveredClassHelper { } for (Function possibleDestructor : possibleDestructors) { - monitor.checkCanceled(); + monitor.checkCancelled(); if (allPossibleConstructorDestructors.contains(possibleDestructor)) { processFoundDestructor(possibleDestructor, calledFromFunction); } @@ -6843,7 +6985,7 @@ public class RecoveredClassHelper { List
calledFunctionsOnList = new ArrayList
(); Set
addresses = addressToCalledFunctions.keySet(); for (Address address : addresses) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function function = addressToCalledFunctions.get(address); @@ -6881,7 +7023,7 @@ public class RecoveredClassHelper { if (!freesBySymbol.isEmpty()) { for (Function function : freesBySymbol) { - monitor.checkCanceled(); + monitor.checkCancelled(); Set thunksTo = getThunksTo(function); operatorDeletesByThunkToFree.addAll(thunksTo); @@ -6907,7 +7049,7 @@ public class RecoveredClassHelper { continue; } for (Address address : thunksToExternalFree) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function function = api.getFunctionAt(address); operatorDeletesByThunkToExternalFree.add(function); @@ -6916,7 +7058,7 @@ public class RecoveredClassHelper { continue; } for (Function thunkToExternalFree : thunksToThunk) { - monitor.checkCanceled(); + monitor.checkCancelled(); // in this case just want the true thunks not the single call functions - get unwinds that way if (thunkToExternalFree.isThunk()) { operatorDeletesByThunkToExternalFree.add(thunkToExternalFree); @@ -6962,7 +7104,7 @@ public class RecoveredClassHelper { Set functionsThatCallCallnewh = new HashSet(); for (Function callnewh : callnewhBySymbol) { - monitor.checkCanceled(); + monitor.checkCancelled(); Set callingFunctions = new HashSet(callnewh.getCallingFunctions(monitor)); @@ -6970,7 +7112,7 @@ public class RecoveredClassHelper { } for (Function malloc : mallocBySymbol) { - monitor.checkCanceled(); + monitor.checkCancelled(); List callingFunctions = new ArrayList(malloc.getCallingFunctions(monitor)); @@ -6979,7 +7121,7 @@ public class RecoveredClassHelper { continue; } for (Function callingFunction : callingFunctions) { - monitor.checkCanceled(); + monitor.checkCancelled(); if (functionsThatCallCallnewh.contains(callingFunction) && !operatorNewsByCallToMallocAndCallnewh.contains(callingFunction)) { operatorNewsByCallToMallocAndCallnewh.add(callingFunction); @@ -6999,7 +7141,7 @@ public class RecoveredClassHelper { SymbolIterator symbolIterator = symbolTable.getSymbolIterator(); while (symbolIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Symbol symbol = symbolIterator.next(); if (!symbol.getName().equals(name)) { continue; @@ -7028,7 +7170,7 @@ public class RecoveredClassHelper { } for (Reference ref : referencesTo) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address address = ref.getFromAddress(); Instruction instruction = program.getListing().getInstructionAt(address); @@ -7070,7 +7212,7 @@ public class RecoveredClassHelper { } for (Function thunk : thunksToThunk) { - monitor.checkCanceled(); + monitor.checkCancelled(); thunksToFunction.add(thunk); } @@ -7094,7 +7236,7 @@ public class RecoveredClassHelper { Iterator recoveredClassIterator = recoveredClasses.iterator(); while (recoveredClassIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = recoveredClassIterator.next(); Function vBaseDestructor = recoveredClass.getVBaseDestructor(); if (vBaseDestructor == null) { @@ -7119,7 +7261,7 @@ public class RecoveredClassHelper { for (RecoveredClass recoveredClass : recoveredClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); allConstructorDestructorFunctions.addAll(recoveredClass.getConstructorList()); allConstructorDestructorFunctions.addAll(recoveredClass.getDestructorList()); @@ -7136,7 +7278,7 @@ public class RecoveredClassHelper { allConstructorDestructorFunctions.removeAll(nonClassInlines); for (Function function : allConstructorDestructorFunctions) { - monitor.checkCanceled(); + monitor.checkCancelled(); makeFunctionThiscall(function); } @@ -7176,7 +7318,7 @@ public class RecoveredClassHelper { for (DataTypeComponent definedComponent : definedComponents) { - monitor.checkCanceled(); + monitor.checkCancelled(); int offset = definedComponent.getOffset() - dataOffset; @@ -7236,7 +7378,7 @@ public class RecoveredClassHelper { Iterator recoveredClassIterator = recoveredClasses.iterator(); while (recoveredClassIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); RecoveredClass recoveredClass = recoveredClassIterator.next(); if (recoveredClass.hasChildClass()) { @@ -7248,7 +7390,7 @@ public class RecoveredClassHelper { } Iterator vfunctionIterator = virtualFunctions.iterator(); while (vfunctionIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function vfunction = vfunctionIterator.next(); // skip the deleting destructors if (deletingDestructors.contains(vfunction)) { @@ -7306,7 +7448,7 @@ public class RecoveredClassHelper { Iterator listIterator = list.iterator(); while (listIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function function = listIterator.next(); if (!listOfUniqueFunctions.contains(function)) { listOfUniqueFunctions.add(function); @@ -7327,7 +7469,7 @@ public class RecoveredClassHelper { Iterator
listIterator = list.iterator(); while (listIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address address = listIterator.next(); if (!listOfUniqueAddresses.contains(address)) { listOfUniqueAddresses.add(address); @@ -7353,7 +7495,7 @@ public class RecoveredClassHelper { for (RecoveredClass recoveredClass : recoveredClasses) { - monitor.checkCanceled(); + monitor.checkCancelled(); List constructorOrDestructorFunctions = recoveredClass.getConstructorOrDestructorFunctions(); @@ -7365,7 +7507,7 @@ public class RecoveredClassHelper { Iterator cdFunctionIterator = constructorOrDestructorFunctions.iterator(); while (cdFunctionIterator.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Function cdFunction = cdFunctionIterator.next(); @@ -7471,7 +7613,7 @@ public class RecoveredClassHelper { int numComponents = vftableData.getNumComponents(); for (int i = 0; i < numComponents; i++) { - monitor.checkCanceled(); + monitor.checkCancelled(); // get the index of the DATA component that corresponds to the function Address functionPointerAddress = vftableData.getComponent(i).getAddress(); @@ -7509,12 +7651,12 @@ public class RecoveredClassHelper { functionAddresses.add(function.getEntryPoint()); for (Address address : functionAddresses) { - monitor.checkCanceled(); + monitor.checkCancelled(); ReferenceIterator referencesTo = refMan.getReferencesTo(address); while (referencesTo.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Reference referenceTo = referencesTo.next(); if (referenceTo.getReferenceType() != RefType.DATA) { @@ -7732,10 +7874,10 @@ public class RecoveredClassHelper { List classStructures = new ArrayList(); for (Category category : categories) { - monitor.checkCanceled(); + monitor.checkCancelled(); DataType[] dataTypes = category.getDataTypes(); for (DataType dataType : dataTypes) { - monitor.checkCanceled(); + monitor.checkCancelled(); // if the data type name is the same as the folder name then // it is the main class structure so add it @@ -7767,7 +7909,7 @@ public class RecoveredClassHelper { } for (Object item : itemsToAdd) { - monitor.checkCanceled(); + monitor.checkCancelled(); if (!mainList.contains(item)) { mainList.add(item); } @@ -7779,7 +7921,7 @@ public class RecoveredClassHelper { List structures = new ArrayList(); for (Object item : list) { - monitor.checkCanceled(); + monitor.checkCancelled(); if (item instanceof Structure) { structures.add((Structure) item); } @@ -7792,7 +7934,7 @@ public class RecoveredClassHelper { List functionDefs = new ArrayList(); for (Object item : list) { - monitor.checkCanceled(); + monitor.checkCancelled(); if (item instanceof FunctionDefinition) { functionDefs.add((FunctionDefinition) item); } @@ -7804,7 +7946,7 @@ public class RecoveredClassHelper { List functions = new ArrayList(); for (Object item : list) { - monitor.checkCanceled(); + monitor.checkCancelled(); if (item instanceof Function) { functions.add((Function) item); } @@ -7840,7 +7982,7 @@ public class RecoveredClassHelper { Collection dataTypesContaining = pointer.getParents(); for (DataType dataTypeContaining : dataTypesContaining) { - monitor.checkCanceled(); + monitor.checkCancelled(); if (!(dataTypeContaining instanceof Structure)) { continue; @@ -7918,7 +8060,7 @@ public class RecoveredClassHelper { int numComponents = vftableStructure.getNumComponents(); for (int i = 0; i < numComponents; i++) { - monitor.checkCanceled(); + monitor.checkCancelled(); DataTypeComponent component = vftableStructure.getComponent(i); if (component.getDataType().equals(pointerToVfunction)) { @@ -7957,7 +8099,7 @@ public class RecoveredClassHelper { SymbolIterator classSymbols = symbolTable.getSymbols(classNamespace); while (classSymbols.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Symbol classSymbol = classSymbols.next(); if (!classSymbol.getName().contains(VFTABLE_LABEL)) { continue; @@ -7998,7 +8140,7 @@ public class RecoveredClassHelper { DataType[] classDataTypes = category.getDataTypes(); for (DataType classDataType : classDataTypes) { - monitor.checkCanceled(); + monitor.checkCancelled(); if (!(classDataType instanceof FunctionDefinition)) { continue; @@ -8231,7 +8373,7 @@ public class RecoveredClassHelper { SymbolIterator symbols = symbolTable.getSymbols(classNamespace); while (symbols.hasNext()) { - monitor.checkCanceled(); + monitor.checkCancelled(); Symbol symbol = symbols.next(); if (symbol.getName().equals("vftable") || symbol.getName().substring(1).startsWith("vftable") || @@ -8313,7 +8455,7 @@ public class RecoveredClassHelper { // the parent class structures with the class vftable pointer then replace the rest of the // parent structure with its internal components for (Integer offset : classVftableOffsets) { - monitor.checkCanceled(); + monitor.checkCancelled(); Address vftableAddress = classOffsetToVftableMap.get(offset); @@ -8332,7 +8474,7 @@ public class RecoveredClassHelper { // components and loop until can replace with the vftable pointer while (true) { - monitor.checkCanceled(); + monitor.checkCancelled(); // if enough empty bytes or can grow the structure - add class vftable pointer boolean addedToStructure = diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/SpecialVtable.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/SpecialVtable.java new file mode 100644 index 0000000000..a401bd5f27 --- /dev/null +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/SpecialVtable.java @@ -0,0 +1,85 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package classrecovery; + +import ghidra.program.model.address.Address; +import ghidra.program.model.listing.Program; +import ghidra.program.model.symbol.Namespace; +import ghidra.util.exception.CancelledException; +import ghidra.util.task.TaskMonitor; + +public class SpecialVtable extends Vtable { + + Address refFromTypeinfos; + + public SpecialVtable(Program program, Address vtableAddress, GccTypeinfoRef typeinfoRef, boolean inExternalMemory, Namespace classNamespace, TaskMonitor monitor) throws CancelledException { + + super(program, vtableAddress, typeinfoRef, true, inExternalMemory, monitor); + this.classNamespace = classNamespace; + } + + @Override + protected void setup() throws CancelledException { + + if(inExternalMemory) { + + refFromTypeinfos = vtableAddress; + isConstruction = false; + isPrimary = true; + typeinfoAddress = vtableAddress; + length = defaultPointerSize; + hasVfunctions = false; + return; + } + + typeinfoRefAddress = vtableAddress.add(defaultPointerSize); + + + setTypeinfoAddress(); + + if(!isValid) { + return; + } + + setTopOffsetValue(); + + if(!isValid) { + return; + } + + isPrimary = true; + + + setHasVfunctions(); + + if(!isValid) { + return; + } + + isConstruction = false; + + classNamespace = typeinfoNamespace; + + + setLength(); + + } + + public Address getRefFromTypeinfos() { + return refFromTypeinfos; + } + +} diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/Typeinfo.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/Typeinfo.java new file mode 100644 index 0000000000..48c7255139 --- /dev/null +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/Typeinfo.java @@ -0,0 +1,52 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package classrecovery; + +import ghidra.program.model.address.Address; +import ghidra.program.model.symbol.Namespace; + +public class Typeinfo { + + private Address address; + private Namespace classNamespace; + private Boolean hasDefinedStructure = false; + + Typeinfo(Address address, Namespace classNamespace){ + this.address = address; + this.classNamespace = classNamespace; + } + + public Address getAddress() { + return address; + } + + public Namespace getNamespace() { + return classNamespace; + } + + /** + * method to define if has defined structure or not + * @param setting true - has defined structure, false - not yet defined, null - not enough memory to defined a structure + */ + private void setHasDefinedStructure(Boolean setting) { + hasDefinedStructure = setting; + } + + public Boolean hasDefinedStructure() { + return hasDefinedStructure; + } + +} diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/TypeinfoRef.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/TypeinfoRef.java new file mode 100644 index 0000000000..c847fa7c24 --- /dev/null +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/TypeinfoRef.java @@ -0,0 +1,52 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package classrecovery; + +import ghidra.program.model.address.Address; + +public class TypeinfoRef { + + private Address address; + private Typeinfo typeinfo; + private Boolean inVtable = null; + + TypeinfoRef(Address address, Typeinfo typeinfo){ + this.address = address; + this.typeinfo = typeinfo; + } + + TypeinfoRef(Address address, Typeinfo typeinfo, Boolean inVtable){ + this.address = address; + this.typeinfo = typeinfo; + this.inVtable = inVtable; + } + + public Address getAddress() { + return address; + } + + public Typeinfo getReferencedTypeinfo() { + return typeinfo; + } + + public void setIsInVtable(Boolean setting) { + inVtable = setting; + } + + public Boolean isInVtable() { + return inVtable; + } +} diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/Vtable.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/Vtable.java new file mode 100644 index 0000000000..78030c76db --- /dev/null +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/Vtable.java @@ -0,0 +1,822 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package classrecovery; + +import java.util.ArrayList; +import java.util.List; + +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressOutOfBoundsException; +import ghidra.program.model.address.AddressSetView; +import ghidra.program.model.address.AddressSpace; +import ghidra.program.model.address.GlobalNamespace; +import ghidra.program.model.data.ArrayDataType; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.DataTypeManager; +import ghidra.program.model.data.LongDataType; +import ghidra.program.model.data.LongLongDataType; +import ghidra.program.model.lang.Register; +import ghidra.program.model.listing.Bookmark; +import ghidra.program.model.listing.BookmarkType; +import ghidra.program.model.listing.Data; +import ghidra.program.model.listing.Function; +import ghidra.program.model.listing.FunctionManager; +import ghidra.program.model.listing.Instruction; +import ghidra.program.model.listing.Listing; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.Memory; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.mem.MemoryBlock; +import ghidra.program.model.symbol.Namespace; +import ghidra.program.model.symbol.SourceType; +import ghidra.program.model.symbol.Symbol; +import ghidra.program.model.symbol.SymbolTable; +import ghidra.util.Msg; +import ghidra.util.exception.CancelledException; +import ghidra.util.task.TaskMonitor; + +public class Vtable { + + private static final String VTABLE_LABEL = "vtable"; + + Program program; + Address vtableAddress; + Boolean isSpecial = null; + GccTypeinfoRef typeinfoRef = null; + Address typeinfoRefAddress = null; + GccTypeinfo typeinfo = null; + Boolean hasVfunctions = null; + Integer numVfunctions = null; + Long topOffsetValue = null; + Address vfunctionTop = null; + Address typeinfoAddress = null; + + Boolean isPrimary = null; + Boolean isConstruction = null; + List internalVtables = new ArrayList(); + List
relatedMainVtables = new ArrayList
(); + boolean inExternalMemory; + Boolean isValid = true; + + Namespace typeinfoNamespace = null; + Namespace classNamespace = null; + Integer length = null; + Vtable primaryVtable = null; + int defaultPointerSize; + SymbolTable symbolTable; + ExtendedFlatProgramAPI extendedFlatAPI; + TaskMonitor monitor; + GlobalNamespace globalNamespace; + FunctionManager functionManager; + DataTypeManager dataTypeManager; + Listing listing; + + + + public Vtable(Program program, Address vtableAddress, GccTypeinfoRef typeinfoRef, boolean isSpecial, boolean inExternalMemory, + Vtable primaryVtable, Boolean isConstruction, TaskMonitor monitor) + throws CancelledException { + + this.program = program; + this.vtableAddress = vtableAddress; + this.typeinfoRef = typeinfoRef; + this.isSpecial = isSpecial; + this.inExternalMemory = inExternalMemory; + this.primaryVtable = primaryVtable; + this.isConstruction = isConstruction; + this.monitor = monitor; + this.typeinfoRefAddress = typeinfoRef.getAddress(); + this.typeinfo = (GccTypeinfo) typeinfoRef.getReferencedTypeinfo(); + this.typeinfoNamespace = typeinfo.getNamespace(); + + AddressSpace addressSpace = vtableAddress.getAddressSpace(); + defaultPointerSize = addressSpace.getPointerSize(); + symbolTable = program.getSymbolTable(); + extendedFlatAPI = new ExtendedFlatProgramAPI(program, monitor); + globalNamespace = (GlobalNamespace) program.getGlobalNamespace(); + functionManager = program.getFunctionManager(); + dataTypeManager = program.getDataTypeManager(); + listing = program.getListing(); + + setup(); + } + + public Vtable(Program program, Address vtableAddress, GccTypeinfoRef typeinfoRef, boolean isSpecial, boolean inExternalMemory, TaskMonitor monitor) + throws CancelledException { + this(program, vtableAddress, typeinfoRef, isSpecial, inExternalMemory, null, null, monitor); + } + + public Vtable(Program program, Address vtableAddress, GccTypeinfoRef typeinfoRef, boolean isSpecial, boolean inExternalMemory, boolean isConstruction, + TaskMonitor monitor) throws CancelledException { + this(program, vtableAddress, typeinfoRef, isSpecial, inExternalMemory, null, isConstruction, monitor); + } + + protected void setup() throws CancelledException { + + checkValidTop(); + + if (!isValid) { + return; + } + + setTopOffsetValue(); + + if (!isValid) { + return; + } + + setIsInternalVtable(); + + if (!isValid) { + return; + } + + figureOutNamespace(); + + setHasVfunctions(); + + if (!isValid) { + return; + } + + // setIsConstructionVtable(); + + if (!isValid) { + return; + } + + setLength(); + + if (!isValid) { + return; + } + + try { + applyVtableData(); + } catch (Exception e) { + isValid = false; + } + + findInternalVtables(); + } + + public boolean equals(Vtable vtable) { + return vtable.getAddress().equals(vtableAddress); + } + + private void checkValidTop() { + + // check for existing vtable name - if has a non-default label that isn't vtable + // then assume not valid + Symbol symbol = symbolTable.getPrimarySymbol(vtableAddress); + if (symbol != null && symbol.getSource() != SourceType.DEFAULT) { + if (symbol.getName().contains(VTABLE_LABEL)) { + isValid = true; + return; + } + isValid = false; + return; + } + + // for ones with no symbol or default symbol check for long value/non address at + // top + // if is an address not valid + // if is not an address may be valid - will need further checks in other methods + Address referencedAddress = getReferencedAddress(vtableAddress); + if (referencedAddress != null) { + isValid = false; + return; + } + // May or may not be valid but so far valid + isValid = true; + } + + public Address getAddress() { + return vtableAddress; + } + + public boolean isExternal() { + return inExternalMemory; + } + + public boolean isValid() { + return isValid; + } + + + public Address getTypeinfoRefAddress() { + return typeinfoRef.getAddress(); + } + + public GccTypeinfo getReferencedTypeinfo() { + return (GccTypeinfo) typeinfoRef.getReferencedTypeinfo(); + } + + protected void setTypeinfoAddress() { + + GccTypeinfo typeinfo = getReferencedTypeinfo(); + typeinfoAddress = typeinfo.getAddress(); + typeinfoNamespace = typeinfo.getNamespace(); + + } + + public Address getTypeinfoAddress() { + return typeinfoAddress; + } + + protected void setTopOffsetValue() { + + try { + Address topOffset = typeinfoRefAddress.subtract(defaultPointerSize); + if (topOffset.getOffset() < vtableAddress.getOffset()) { + Msg.debug(this,"No offset field in vtable at " + vtableAddress.toString()); + isValid = false; + return; + } + + topOffsetValue = extendedFlatAPI.getLongValueAt(topOffset); + } catch (IllegalArgumentException e) { + Msg.debug(this, "Invalid vtable: " + vtableAddress.toString() + " No offset field"); + isValid = false; + } + } + + private void setIsInternalVtable() { + + if (topOffsetValue == null) { + isValid = false; + return; + } + + // if it has an existing label that is exactly "vtable" then set it true and + // return + Symbol primarySymbol = symbolTable.getPrimarySymbol(vtableAddress); + if (primarySymbol != null && primarySymbol.getName().equals("vtable")) { + isPrimary = true; + return; + + } + + // otherwise, use the topOffsetValue to figure it out + if (topOffsetValue == 0L) { + isPrimary = true; + } else { + isPrimary = false; + } + } + + public Boolean isPrimary() { + + if (isPrimary == null) { + isValid = false; + return null; + } + + return isPrimary; + } + + public void setNumVfunctions(int num) { + numVfunctions = num; + } + + public Integer getNumVfunctions() { + + if (numVfunctions == null) { + isValid = false; + return null; + } + return numVfunctions; + } + + protected void setHasVfunctions() throws CancelledException { + + Address typeinfoRefAddress = getTypeinfoRefAddress(); + if (isPrimary == null) { + isValid = false; + return; + } + + try { + Address possVfunctionTop = typeinfoRefAddress.add(defaultPointerSize); + + numVfunctions = getNumFunctionPointers(possVfunctionTop, true, false); + if (numVfunctions == 0) { + hasVfunctions = false; + } else { + hasVfunctions = true; + vfunctionTop = possVfunctionTop; + } + } catch (AddressOutOfBoundsException e) { + hasVfunctions = false; + } + + } + + private int getNumFunctionPointers(Address topAddress, boolean allowNullFunctionPtrs, + boolean allowDefaultRefsInMiddle) throws CancelledException { + + int numFunctionPointers = 0; + Address address = topAddress; + + // if it has a primary non-default symbol and it isn't "vftable" then it isn't a vftable + Symbol primarySymbol = symbolTable.getPrimarySymbol(topAddress); + if(primarySymbol != null && primarySymbol.getSource() != SourceType.DEFAULT && !primarySymbol.getName().contains("vftable")) { + return numFunctionPointers; + } + MemoryBlock currentBlock = program.getMemory().getBlock(topAddress); + + boolean stillInCurrentTable = true; + while (address != null && currentBlock.contains(address) && stillInCurrentTable + && (isPossibleFunctionPointer(address) || (allowNullFunctionPtrs && isPossibleNullPointer(address)))) { + + numFunctionPointers++; + address = address.add(defaultPointerSize); + Symbol symbol = symbolTable.getPrimarySymbol(address); + if (symbol == null) { + continue; + } + // never let non-default refs in middle + if (symbol.getSource() != SourceType.DEFAULT) { + stillInCurrentTable = false; + } + + // if it gets here it is default + if (!allowDefaultRefsInMiddle) { + stillInCurrentTable = false; + } + } + + //NEW: TESTING Don't allow single null pointer at top of vftable + //OR test to see if nulls then typeinfo ptr +// if(isPossibleNullPointer(topAddress) && numFunctionPointers == 1) { +// return 0; +// } + + // check to see if last is null ptr and next addr after that is typeinfo ref - indicating the null is really top of next vtable + Address lastAddress = topAddress.add((numFunctionPointers-1)*defaultPointerSize); + if(isPossibleNullPointer(lastAddress) && (isTypeinfoRef(lastAddress.add(defaultPointerSize)))){ + numFunctionPointers--; + } + return numFunctionPointers; + } + + private boolean isTypeinfoRef(Address addr) { + + Address referencedAddress = getReferencedAddress(addr); + if(referencedAddress == null) { + return false; + } + Data data = program.getListing().getDataAt(referencedAddress); + if(data == null) { + return false; + } + + if(data.getBaseDataType().getName().contains("ClassTypeInfoStructure")) { + return true; + } + return false; + } + + /** + * Method to determine if there are enough zeros to make a null poihnter and no + * references into or out of the middle + * + * @param address the given address + * @return true if the given address could be a valid null pointer, false if not + */ + private boolean isPossibleNullPointer(Address address) throws CancelledException { + if (!extendedFlatAPI.hasNumZeros(address, defaultPointerSize)) { + return false; + } + return true; + } + + /** + * Method to determine if the given address contains a possible function pointer + * + * @param address the given address + * @return true if the given address contains a possible function pointer or + * false otherwise + * @throws CancelledException if cancelled + */ + private boolean isPossibleFunctionPointer(Address address) throws CancelledException { + + // TODO: make one that works for all casea in helper + // TODO: make sure it recognizes the external functions + + long longValue = extendedFlatAPI.getLongValueAt(address); + + Register lowBitCodeMode = program.getRegister("LowBitCodeMode"); + if (lowBitCodeMode != null) { + longValue = longValue & ~0x1; + } + + Address possibleFunctionPointer = null; + + try { + possibleFunctionPointer = address.getNewAddress(longValue); + } catch (AddressOutOfBoundsException e) { + return false; + } + + if (possibleFunctionPointer == null) { + return false; + } + + Function function = extendedFlatAPI.getFunctionAt(possibleFunctionPointer); + if (function != null) { + return true; + } + + AddressSetView executeSet = program.getMemory().getExecuteSet(); + + if (!executeSet.contains(possibleFunctionPointer)) { + return false; + } + + Instruction instruction = extendedFlatAPI.getInstructionAt(possibleFunctionPointer); + if (instruction != null) { + extendedFlatAPI.createFunction(possibleFunctionPointer, null); + return true; + + } + + boolean disassemble = extendedFlatAPI.disassemble(possibleFunctionPointer); + if (disassemble) { + + // check for the case where there is conflicting data at the thumb offset + // function + // pointer and if so clear the data and redisassemble and remove the bad + // bookmark + long originalLongValue = extendedFlatAPI.getLongValueAt(address); + if (originalLongValue != longValue) { + Address offsetPointer = address.getNewAddress(originalLongValue); + if (extendedFlatAPI.getDataAt(offsetPointer) != null) { + extendedFlatAPI.clearListing(offsetPointer); + disassemble = extendedFlatAPI.disassemble(address); + + Bookmark bookmark = getBookmarkAt(possibleFunctionPointer, BookmarkType.ERROR, "Bad Instruction", + "conflicting data"); + if (bookmark != null) { + extendedFlatAPI.removeBookmark(bookmark); + } + } + } + + extendedFlatAPI.createFunction(possibleFunctionPointer, null); + return true; + } + return false; + } + + private Bookmark getBookmarkAt(Address address, String bookmarkType, String category, String commentContains) + throws CancelledException { + + Bookmark[] bookmarks = program.getBookmarkManager().getBookmarks(address); + + for (Bookmark bookmark : bookmarks) { + monitor.checkCancelled(); + + if (bookmark.getType().getTypeString().equals(bookmarkType) && bookmark.getCategory().equals(category) + && bookmark.getComment().contains(commentContains)) { + return bookmark; + } + } + return null; + } + + public void setHasVfunctions(boolean flag) { + hasVfunctions = flag; + } + + public boolean hasVfunctions() { + return hasVfunctions; + } + + public Address getVfunctionTop() { + return vfunctionTop; + } + + protected void setLength() { + + if (hasVfunctions == null) { + isValid = false; + return; + } + if (!hasVfunctions) { + length = (int) (typeinfoRefAddress.getOffset() + defaultPointerSize - vtableAddress.getOffset()); + return; + } + + if (numVfunctions == null || vfunctionTop == null) { + isValid = false; + return; + } + + Address endAddr = vfunctionTop.add(numVfunctions * defaultPointerSize); + length = (int) (endAddr.getOffset() - vtableAddress.getOffset()); + + } + + private void addToLength(int amountToAdd) { + length = length + amountToAdd; + } + + public int getLength() { + return length; + } + + private void findInternalVtables() throws CancelledException { + + // if the current table is already an internal vtable there won't be any + // internal ones in it + if (!isPrimary) { + return; + } + + boolean keepChecking = true; + + int limit = length; + + while (keepChecking) { + + monitor.checkCancelled(); + + Address nextAddr = vtableAddress.add(length); + + + Address typeinfoAddr = typeinfo.getAddress(); + + int alignment = nextAddr.getSize()/8; + Address nextTypeinfoRefAddr = getNextReferenceTo(nextAddr, typeinfoAddr, alignment, limit); + if(nextTypeinfoRefAddr == null) { + keepChecking = false; + continue; + } + + GccTypeinfoRef internalTypenfoRef = new GccTypeinfoRef(nextTypeinfoRefAddr, typeinfo, true); + + Vtable possibleInternalVtable = new Vtable(program, nextAddr,internalTypenfoRef, isSpecial, inExternalMemory, + this, isConstruction, monitor); + if (!possibleInternalVtable.isValid()) { + keepChecking = false; + continue; + } + + if (possibleInternalVtable.isPrimary()) { + keepChecking = false; + continue; + } + + Namespace internalVtableNamespace = possibleInternalVtable.getNamespace(); + if (internalVtableNamespace != null && internalVtableNamespace.equals(classNamespace)) { + addInternalVtable(possibleInternalVtable); + } else { + keepChecking = false; + } + + } + } + + private Address getNextReferenceTo(Address startAddress, Address refdAddress, int alignment, int limit) { + + int offset = alignment; + while(offset < limit) { + Address addr = startAddress.add(offset); + Address referencedAddress = getReferencedAddress(addr); + if(referencedAddress != null && referencedAddress.equals(refdAddress)) { + return addr; + } + offset += alignment; + } + return null; + } + + private void addInternalVtable(Vtable internalVtable) { + internalVtables.add(internalVtable); + addToLength(internalVtable.getLength()); + } + + public List getInternalVtables() { + return internalVtables; + } + + + // TODO: put in helper or ext api + private boolean inExternalBlock(Address address) { + + MemoryBlock externalBlock = getExternalBlock(); + if (externalBlock == null) { + return false; + } + if (externalBlock.contains(address)) { + return true; + } + return false; + + } + + private MemoryBlock getExternalBlock() { + return program.getMemory().getBlock("EXTERNAL"); + } + + + public void setIsConstructionVtable(Boolean setting) { + isConstruction = setting; + } + + public Boolean isConstructionVtable() { + return isConstruction; + } + + private void figureOutNamespace() { + + if(isConstruction == null) { + setNamespace(globalNamespace); + return; + } + + // if construction vtable can't figure out from within vtable object + // have to assign later after further inspection of vtts and other info + if (isConstruction != null && isConstructionVtable()) { + setNamespace(globalNamespace); + return; + } + + if (isPrimary()) { + setNamespace(typeinfoNamespace); + return; + } + + // if not primary and the primary has same namespace then it is an internal + // vtable and can + // set the namespace to the typeinfo namespace + if (!primaryVtable.getNamespace().isGlobal() && primaryVtable.getNamespace().equals(typeinfoNamespace)) { + setNamespace(typeinfoNamespace); + return; + } + + } + + // for setting namespaces after vtable is created when they can't + // be determined by looking at internals of current vtable + public void setNamespace(Namespace namespace) { + + classNamespace = namespace; + for(Vtable internalVtable : internalVtables) { + internalVtable.setNamespace(namespace); + } + } + + public Namespace getNamespace() { + return classNamespace; + } + + protected boolean applyVtableData() throws CancelledException, Exception { + + Data dataAt = listing.getDataAt(vtableAddress); + + // first check to see it is an erroneous vtable that has been made a byte array + // if so, clear it and start looking for the typeinfo reference + //TODO: check !isDefined and use known length to clear + if (dataAt != null && dataAt.isArray()) { + listing.clearCodeUnits(vtableAddress, vtableAddress, false); + } + + if (dataAt != null && !dataAt.getDataType().getName().equals("long")) { + listing.clearCodeUnits(vtableAddress, vtableAddress, false); + } + + // create the typeinfo pointer if there isn't already one + Data typeinfoPtr = listing.getDataAt(typeinfoRefAddress); + if (typeinfoPtr == null || !typeinfoPtr.isDefined()) { + DataType nullPointer = dataTypeManager.getPointer(null); + + listing.createData(typeinfoRefAddress, nullPointer); + + } + + // create longs from top of vtable to the typeinfo reference + createLongs(this.vtableAddress, typeinfoRefAddress); + + int numFunctionPointers = getNumVfunctions(); + + if (numFunctionPointers != 0) { + + Address vftableAddress = getVfunctionTop(); + + createVftableArray(vftableAddress, numFunctionPointers); + } + + return true; + } + + public Data createVftableArray(Address vftableAddress, int numFunctionPointers) + throws CancelledException, AddressOutOfBoundsException { + + listing.clearCodeUnits(vftableAddress, + vftableAddress.add((numFunctionPointers * defaultPointerSize - 1)), false); + + DataType pointerDataType = dataTypeManager.getPointer(null); + ArrayDataType vftableArrayDataType = new ArrayDataType(pointerDataType, numFunctionPointers, + defaultPointerSize); + try { + Data vftableArrayData = listing.createData(vftableAddress, vftableArrayDataType); + return vftableArrayData; + } catch (Exception e) { + return null; + } + + } + + /** + * Method to create a series of long data types from the given start address to + * the given end 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) throws CancelledException, Exception { + + DataType longDT = new LongDataType(dataTypeManager); + if (defaultPointerSize == 8) { + longDT = new LongLongDataType(); + } + int offset = 0; + Address address = start; + while (address != null && !address.equals(end)) { + + listing.clearCodeUnits(address, address.add(defaultPointerSize - 1),false); + listing.createData(address, longDT); + offset += defaultPointerSize; + address = getAddress(start, offset); + } + + } + + /** + * Method to get address at address + offset + * + * @param address the given address + * @param offset the given offset + * @return the address at address + offset or null if it doesn't exist + */ + private Address getAddress(Address address, int offset) { + try { + Address newAddress = address.add(offset); + return newAddress; + } catch (AddressOutOfBoundsException e) { + return null; + } + } + + private Address getReferencedAddress(Address address) { + + int addressSize = address.getSize(); + Memory memory = program.getMemory(); + try { + + if (addressSize == 32) { + long offset32 = memory.getInt(address); + Address newAddr = address.getNewAddress(offset32); + if(memory.contains(newAddr)) { + return newAddr; + } + return null; + + } + else if (addressSize == 64) { + + long offset64 = memory.getLong(address); + Address newAddr = address.getNewAddress(offset64); + if(memory.contains(newAddr)) { + return newAddr; + } + return null; + + } + else { + return null; + } + } + catch (MemoryAccessException e) { + return null; + } + } + +} diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/Vtt.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/Vtt.java new file mode 100644 index 0000000000..f140d46660 --- /dev/null +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/Vtt.java @@ -0,0 +1,54 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package classrecovery; + +import java.util.ArrayList; +import java.util.List; + +import ghidra.program.model.address.Address; +import ghidra.program.model.symbol.Namespace; + +public class Vtt { + + Address vttAddress; + Namespace namespace; + List
pointers = new ArrayList
(); + + public Vtt(Address vttAddress, Namespace namespace){ + this.vttAddress = vttAddress; + this.namespace = namespace; + } + + public Address getAddress() { + return vttAddress; + } + + public Namespace getNamespace() { + return namespace; + } + + public void addPointerToList(Address pointer) { + pointers.add(pointer); + } + + public boolean containsPointer(Address pointer) { + return(pointers.contains(pointer)); + } + + public int getNumPtrs() { + return pointers.size(); + } +}