diff --git a/Ghidra/Features/Base/ghidra_scripts/GccRttiAnalysisScript.java b/Ghidra/Features/Base/ghidra_scripts/GccRttiAnalysisScript.java index 2979a98e17..a88f161c0d 100644 --- a/Ghidra/Features/Base/ghidra_scripts/GccRttiAnalysisScript.java +++ b/Ghidra/Features/Base/ghidra_scripts/GccRttiAnalysisScript.java @@ -680,7 +680,6 @@ public class GccRttiAnalysisScript extends GhidraScript { /** * 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 void processVtables() throws Exception { diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionDefinitionUpdatesScript.java b/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionDefinitionUpdatesScript.java index 03a6cc09b0..d949dd98eb 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionDefinitionUpdatesScript.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionDefinitionUpdatesScript.java @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -// Script to apply any changes the user has made to class virtual function definitions, ie ones they -// have edited in the data type manager. To run the script, put the cursor on any member of the +// Script to apply any changes the user has made to recovered class virtual function definitions +// edited in the data type manager. To run the script, put the cursor on any member of the // desired class in the listing then run the script. For each function definition in the given class // that differs from the associated function signature in the listing, the script will update the -// listing function signatures of any related virtual vunctions (ie parents and children) and update -// related data types such as function definitions of the given class and related classes and also -// field names in related vftable structures. +// listing function signatures of any related virtual functions belonging to parent and children +// classes. It will also update related data types including function definitions and vftable structures. // Note: The script will not work if the vftable structures were not originally applied to // the vftables using the RecoverClassesFromRTTIScript. -// At some point, the Ghidra API will be updated to do this automatically instead of needing the script to do so. +// At some point, the Ghidra API will be updated to do this automatically instead of needing the +// script to do so. //@category C++ import java.util.List; diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionSignatureUpdatesScript.java b/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionSignatureUpdatesScript.java index a7b096208c..3db3b3c858 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionSignatureUpdatesScript.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionSignatureUpdatesScript.java @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -// Script to apply any changes the user has made to class virtual function signatures, ie ones they -// have edited in the listing. To run the script, put the cursor on any member of the desired class in +// Script to apply any changes the user has made to recovered class virtual function signatures +// edited in the listing. To run the script, put the cursor on any member of the desired class in // the listing then run the script. For each function signature in the given class that differs from // the associated function definition in the data type manager, the script will update the listing -// function signatures of any related virtual vunctions (ie parents and children) and update related -// data types such as function definitions of the given class and related classes and also field names -// in related vftable structures. +// function signatures of any related virtual functions belonging to parents and children classes. +// It will also update related data types including function definitions and vftable structures. // Note: The script will not work if the vftable structures were not originally applied to // the vftables using the RecoverClassesFromRTTIScript. -// At some point, the Ghidra API will be updated to do this automatically instead of needing the script to do so. +// At some point, the Ghidra API will be updated to do this automatically instead of needing the +// script to do so. //@category C++ import java.util.List; diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java b/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java index 506234b8a4..5e4078d690 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java @@ -35,18 +35,20 @@ // this script and default vfunctions named by this script are likely to change in the future // once an official design for Object Oriented representation is determined. // NOTE: Windows class recovery is more complete and tested than gcc class recovery, which is still -// in early stages of development. Gcc class data types have not been recovered yet but if the program -// has DWARF, there will be some amount of data recovered by the DWARF analyzer in the DWARF data folder. +// in early stages of development. Gcc class data types are only recovered for classes without multiple or +// virtual inheritance but if the program contains DWARF, there will be some amount of data recovered +// by the DWARF analyzer. // NOTE: For likely the best results, run this script on freshly analyzed programs. No testing has been // done on user marked-up programs. // NOTE: After running this script if you edit function signatures in the listing for a particular -// class and wish to update the corresponding class data (function definition data types, vftable +// class and wish to update the corresponding class data function definition data types (vftable // structure field names, ...) then you can run the ApplyClassFunctionSignatureUpdatesScript.java -// to have it do so for you. +// to have it do so for you. See that script's description for more info. // Conversely, if you update a particular class's function definitions in the data type manager and // wish to have related function signatures in the listing updated, as well as other data types that -// are related, then run the ApplyClassFunctionDefinitionsUpdatesScript.java to do so. At some point, -// the Ghidra API will be updated to do this all automatically instead of needing the scripts to do so. +// are related, then run the ApplyClassFunctionDefinitionsUpdatesScript.java to do so. See that script's +// description for more info. At some point, the Ghidra API will be updated to do the updates +// automatically instead of needing the mentioned scripts to do so. //@category C++ @@ -152,6 +154,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { if (isWindows()) { + isPDBLoaded = isPDBLoadedInProgram(); nameVfunctions = !isPDBLoaded; recoverClassesFromRTTI = new RTTIWindowsClassRecoverer(currentProgram, @@ -159,7 +162,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS, nameVfunctions, isPDBLoaded, monitor); } else if (isGcc()) { - // for now assume gcc has named vfunctions until a way to check is developed + nameVfunctions = true; recoverClassesFromRTTI = new RTTIGccClassRecoverer(currentProgram, currentLocation, state.getTool(), this, BOOKMARK_FOUND_FUNCTIONS, @@ -176,7 +179,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { return; } - // possibly more picky subtype than just checking windows/gcc if (!recoverClassesFromRTTI.isValidProgramType()) { println("This script will not work on this program type"); return; @@ -465,9 +467,41 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { */ private boolean isGcc() { - isGcc = + boolean isELF = currentProgram.getExecutableFormat().contains("ELF"); + if (!isELF) { + return false; + } + + boolean isCompilerSpecGcc = currentProgram.getCompilerSpec().getCompilerSpecID().getIdAsString().equalsIgnoreCase( "gcc"); + if (isCompilerSpecGcc) { + return true; + } + + MemoryBlock commentBlock = currentProgram.getMemory().getBlock(".comment"); + if (commentBlock == null) { + return false; + } + + if (!commentBlock.isLoaded()) { + return false; + } + + + // check memory bytes in block for GCC: bytes + byte[] gccBytes = { (byte) 0x47, (byte) 0x43, (byte) 0x43, (byte) 0x3a }; + byte[] maskBytes = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }; + + Address found = currentProgram.getMemory().findBytes(commentBlock.getStart(), + commentBlock.getEnd(), gccBytes, maskBytes, true, monitor); + if (found == null) { + isGcc = false; + } + else { + isGcc = true; + } + return isGcc; } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java index f5644b7180..85e3835bd4 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java @@ -51,6 +51,10 @@ import ghidra.util.task.TaskMonitor; public class RTTIGccClassRecoverer extends RTTIClassRecoverer { private static final String VTABLE_LABEL = "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 classToTypeinfoMap = new HashMap(); Address class_type_info_vtable = null; @@ -115,6 +119,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { figureOutClassDataMembers(recoveredClasses); + createAndApplyClassStructures(recoveredClasses); + return recoveredClasses; } catch (CancelledException e) { @@ -132,31 +138,50 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { private boolean isGcc() { - boolean isGcc = + boolean isELF = program.getExecutableFormat().contains("ELF"); + if (!isELF) { + return false; + } + + boolean isCompilerSpecGcc = program.getCompilerSpec().getCompilerSpecID().getIdAsString().equalsIgnoreCase("gcc"); - return isGcc; + if (isCompilerSpecGcc) { + return true; + } + + MemoryBlock commentBlock = program.getMemory().getBlock(".comment"); + if (commentBlock == null) { + return false; + } + + if (!commentBlock.isLoaded()) { + return false; + } + + // check memory bytes in block for GCC: bytes + 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); + if (found == null) { + return false; + } + return true; + } /** * Method to check for at least one special RTTI vtable - * @return - * @throws CancelledException + * @return true if the program has at least one special vtable, false if none + * @throws CancelledException if cancelled */ private boolean hasSpecialVtable() throws CancelledException { boolean hasSpecialVtable = createSpecialVtables(); return hasSpecialVtable; -// class_type_info_vtable = findSpecialVtable("__cxxabiv1", "__class_type_info"); -// si_class_type_info_vtable = findSpecialVtable("__cxxabiv1", "__si_class_type_info"); -// vmi_class_type_info_vtable = -// findSpecialVtable("__cxxabiv1", "__vmi_class_type_info"); -// if (class_type_info_vtable == null && si_class_type_info_vtable == null && -// vmi_class_type_info_vtable == null) { -// -// return false; -// } -// return true; } private Address findSpecialVtable(String namespace, String name) throws CancelledException { @@ -209,19 +234,12 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { private List processGccRTTI() throws CancelledException, Exception { - // attempt to find the three special typeinfo structs and vtables -// boolean continueProcessing = findSpecialTypeinfosAndVtables(); -// if (!continueProcessing) { -// return null; -// } + // create rtti vtables and typeinfo structs // find the three special vtables and replace the incorrectly made array with // data types found in vtable - //TODO: *****change to not be a script - make another class and call from here and from script - //runScript("GccRttiAnalysisScript.java"); createGccRttiData(); - // find all typeinfo symbols and get their class namespace and create RecoveredClass object List typeinfoSymbols = extraUtils.getListOfSymbolsInAddressSet( program.getAddressFactory().getAddressSet(), "typeinfo", true); @@ -232,7 +250,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // process vtables and create classes for the vtables that have no typeinfo List vftableSymbols = findVftablesFromVtables(); - Msg.debug(this, "Found " + vftableSymbols.size() + "vftableSymbols"); + if (DEBUG) { + Msg.debug(this, "Found " + vftableSymbols.size() + "vftableSymbols"); + } List recoveredClasses = recoverClassesFromVftables(vftableSymbols, true, true); @@ -260,7 +280,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } // add properties and parents to each class - Msg.debug(this, "Found " + typeinfoSymbols.size() + " typeinfo symbols"); + if (DEBUG) { + Msg.debug(this, "Found " + typeinfoSymbols.size() + " typeinfo symbols"); + } Iterator typeinfoIterator = typeinfoSymbols.iterator(); while (typeinfoIterator.hasNext()) { @@ -283,73 +305,105 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // we don't know yet if this class has vftable so just add without for now if (recoveredClass == null) { // this shoudln't be null at this point - Msg.debug(this, "Shouldn't be a null class here: " + classNamespace.getName()); + if (DEBUG) { + Msg.debug(this, "Shouldn't be a null class here: " + classNamespace.getName()); + } recoveredClass = addNoVftableClass(classNamespace); recoveredClasses.add(recoveredClass); } Address specialTypeinfoRef = extraUtils.getSingleReferencedAddress(typeinfoAddress); if (specialTypeinfoRef == null) { - Msg.debug(this, - "No special typeinfo reference found. Cannot process typeinfo struct at " + - typeinfoAddress.toString()); + if (DEBUG) { + Msg.debug(this, + "No special typeinfo reference found. Cannot process typeinfo struct at " + + typeinfoAddress.toString()); + } continue; } if (!isSpecialTypeinfo(specialTypeinfoRef)) { - 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; + // 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)) { + if (specialTypeinfoRef.equals(class_type_info) || + specialTypeinfoRef.equals(class_type_info_vtable)) { nonInheritedGccClasses.add(recoveredClass); continue; } // 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)) { + if (specialTypeinfoRef.equals(si_class_type_info) || + specialTypeinfoRef.equals(si_class_type_info_vtable)) { singleInheritedGccClasses.add(recoveredClass); RecoveredClass parentClass = getSiClassParent(typeinfoAddress); if (parentClass != null) { - Msg.debug(this, - recoveredClass.getName() + " adding parent " + parentClass.getName()); + if (DEBUG) { + Msg.debug(this, + recoveredClass.getName() + " adding parent " + parentClass.getName()); + } updateClassWithParent(parentClass, recoveredClass); if (!recoveredClasses.contains(parentClass)) { - Msg.debug(this, recoveredClass.getName() + - " adding parent I didn't know about" + parentClass.getName()); + if (DEBUG) { + Msg.debug(this, recoveredClass.getName() + + " adding an unknown parent " + parentClass.getName()); + } recoveredClasses.add(parentClass); } } else { - Msg.debug(this, "Could not get si parent from typeinfoAddress " + - typeinfoAddress.toString()); + if (DEBUG) { + Msg.debug(this, "Could not get si parent from typeinfoAddress " + + typeinfoAddress.toString()); + } } continue; } - if (specialTypeinfoRef.equals(vmi_class_type_info)) { + if (specialTypeinfoRef.equals(vmi_class_type_info) || + specialTypeinfoRef.equals(vmi_class_type_info_vtable)) { multiInheritedGccClasses.add(recoveredClass); recoveredClass.setHasMultipleInheritance(true); - recoveredClass.setHasParentClass(true); - // TODO: get info out of the flags in the typeinfo for this class -// if (recoveredClass.inheritsVirtualAncestor()) { -// recoveredClass.setHasMultipleVirtualInheritance(true); -// } + + if (recoveredClass.inheritsVirtualAncestor()) { + recoveredClass.setHasMultipleVirtualInheritance(true); + } List parents = addGccClassParents(recoveredClass, typeinfoAddress); + if (!recoveredClasses.containsAll(parents)) { - Msg.debug(this, - "missing some parents from " + recoveredClass.getName() + " on list"); + if (DEBUG) { + Msg.debug(this, + "missing some parents from " + recoveredClass.getName() + " on list"); + } } // newNonVftableClasses = // addMissingClasses(parents, newNonVftableClasses, recoveredClasses); @@ -366,9 +420,6 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { Msg.debug(this, "Processing class " + recoveredClass.getName()); List
vftableAddresses = recoveredClass.getVftableAddresses(); - if (vftableAddresses.isEmpty()) { - Msg.debug(this, recoveredClass.getName() + " has no vftable"); - } Iterator
vftableAddressIterator = vftableAddresses.iterator(); while (vftableAddressIterator.hasNext()) { @@ -382,9 +433,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } - Msg.debug(this, "Gets to create called function map."); createCalledFunctionMap(recoveredClasses); - Msg.debug(this, "Gets to assign c/ds."); + assignConstructorsAndDestructorsUsingExistingName(recoveredClasses); return recoveredClasses; @@ -393,9 +443,14 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { private void createGccRttiData() throws CancelledException, Exception { - // find the three special vtables and replace the incorrectly made array with - // data types found in vtable - //createSpecialVtables(); + // TODO: find typeinfo's using other means besides their names since in static case they + // aren't named + // TODO: either check for DWARF and do below if dwarf and another method to find them first + // if not dwarf or combine and either way they are found - immediately call the create typeinfo struct + // but for one at a time. + // remove the ones in the list that are in the EXTERNAL (space or any non-loaded sapce) + // but keep the special ones on symbol list or maybe removet hem here too then don't have + // to keep skipping them later // find all typeinfo symbols and get their class namespace and create RecoveredClass object List typeinfoSymbols = extraUtils.getListOfSymbolsInAddressSet( @@ -410,7 +465,6 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { /** * 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 void processVtables() throws Exception { @@ -459,8 +513,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // find the special type info ref Address typeinfoAddress = findNextTypeinfoRef(vtableAddress); if (typeinfoAddress == null) { - Msg.debug(this, vtableNamespace.getName() + - " vtable has no typeinfo ref after vtable at " + vtableAddress.toString()); + if (DEBUG) { + Msg.debug(this, vtableNamespace.getName() + + " vtable has no typeinfo ref after vtable at " + vtableAddress.toString()); + } return; } @@ -764,29 +820,6 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { return false; } - - /** - * Method to find the (up to three) special gcc vtables and replace the incorrectly made array with the - * correct data types. Also creates a type info symbol at the correct offset in the table. - * @throws CancelledException if cancelled - */ - private void createSpecialVtablesOld() throws CancelledException { - - if (class_type_info_vtable != null) { - class_type_info = createSpecialVtable(class_type_info_vtable); - } - - if (si_class_type_info_vtable != null) { - si_class_type_info = createSpecialVtable(si_class_type_info_vtable); - } - - if (vmi_class_type_info_vtable != null) { - vmi_class_type_info = createSpecialVtable(vmi_class_type_info_vtable); - } - - return; - } - /** * Method to replace the array incorrectly placed at special vftable with longs followed by * typeinfo label @@ -893,22 +926,39 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { 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; + } Address specialTypeinfoRef = extraUtils.getSingleReferencedAddress(typeinfoAddress); if (specialTypeinfoRef == null) { - Msg.debug(this, - "No special typeinfo reference found. Cannot process typeinfo struct at " + - typeinfoAddress.toString()); + if (DEBUG) { + Msg.debug(this, + "No special typeinfo reference found. Cannot process typeinfo struct at " + + typeinfoAddress.toString()); + } continue; } if (!isSpecialTypeinfo(specialTypeinfoRef)) { - continue; + // 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; + } } try { // create a "no inheritance" struct here - if (specialTypeinfoRef.equals(class_type_info)) { + if (specialTypeinfoRef.equals(class_type_info) || + specialTypeinfoRef.equals(class_type_info_vtable)) { api.clearListing(typeinfoAddress, typeinfoAddress.add(classTypeInfoStructure.getLength())); api.createData(typeinfoAddress, classTypeInfoStructure); @@ -916,7 +966,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } // create a "single inheritance" struct here - if (specialTypeinfoRef.equals(si_class_type_info)) { + if (specialTypeinfoRef.equals(si_class_type_info) || + specialTypeinfoRef.equals(si_class_type_info_vtable)) { api.clearListing(typeinfoAddress, typeinfoAddress.add(siClassTypeInfoStructure.getLength() - 1)); api.createData(typeinfoAddress, siClassTypeInfoStructure); @@ -924,7 +975,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } // create a "virtual multip inheritance" struct here - if (specialTypeinfoRef.equals(vmi_class_type_info)) { + if (specialTypeinfoRef.equals(vmi_class_type_info) || + specialTypeinfoRef.equals(vmi_class_type_info_vtable)) { // get num base classes int offsetOfNumBases = 2 * defaultPointerSize + 4; @@ -1060,22 +1112,31 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { extraUtils.getAddress(typeinfoAddress, inheritanceTypeFlagOffset); if (inheritanceFlagAddress == null) { - //TODO: throw exception - Msg.debug(this, "ERROR: Could not access address " + typeinfoAddress.toString() + - " plus offset " + inheritanceTypeFlagOffset); + if (DEBUG) { + Msg.debug(this, "ERROR: Could not access address " + typeinfoAddress.toString() + + " plus offset " + inheritanceTypeFlagOffset); + } return parentClassList; } - // TODO: process the inheritance flag + // process the multiple inheritance flag try { int inheritanceFlagValue = api.getInt(inheritanceFlagAddress); - Msg.debug(this, - inheritanceFlagAddress.toString() + " inheritanceFlag = " + inheritanceFlagValue); + if (inheritanceFlagValue == 0) { + recoveredClass.hasMultipleInheritance(); + } + // TODO: add flags to class for non-diamond repeated and diamond shape types + + if (DEBUG) { + Msg.debug(this, inheritanceFlagAddress.toString() + " inheritanceFlag = " + + inheritanceFlagValue); + } } catch (MemoryAccessException e) { Msg.debug(this, "couldn't get int at address " + inheritanceFlagAddress.toString()); } + int baseClassArrayOffset = defaultPointerSize * 3; Data baseClassArrayData = typeinfoStructure.getComponentAt(baseClassArrayOffset); @@ -1083,7 +1144,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { !baseClassArrayData.getBaseDataType().getName().startsWith( "BaseClassTypeInfoStructure")) { - // TODO: throw exception + if (DEBUG) { + Msg.debug(this, "Could not acess baseClassArray at " + + typeinfoStructure.toString() + baseClassArrayOffset); + } return parentClassList; } @@ -1103,8 +1167,11 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { RecoveredClass parentClass = getParentClassFromParentTypeInfoRef(parentRefAddress); if (parentClass != null) { - Msg.debug(this, - recoveredClass.getName() + " adding vmi parent " + parentClass.getName()); + if (DEBUG) { + Msg.debug(this, + recoveredClass.getName() + " adding vmi parent " + parentClass.getName()); + } + updateClassWithParent(parentClass, recoveredClass); parentClassList.add(parentClass); } @@ -1142,7 +1209,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } } - Msg.debug(this, recoveredClass.getName() + " has " + numParents + " parents"); + if (DEBUG) { + Msg.debug(this, recoveredClass.getName() + " has " + numParents + " parents"); + } + return parentClassList; } @@ -1158,8 +1228,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { Address parentTypeinfoRef = extraUtils.getAddress(typeinfoAddress, offset); if (parentTypeinfoRef == null) { - Msg.debug(this, "ERROR: Could not access address " + typeinfoAddress.toString() + - " plus offset " + offset); + if (DEBUG) { + Msg.debug(this, "ERROR: Could not access address " + typeinfoAddress.toString() + + " plus offset " + offset); + } return null; } @@ -1253,72 +1325,6 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { return true; } - /** - * Method to find the (up to three) special gcc typeinfos and vtables - * @return true if all found tables have a typeinfo symbol created successfully - * @throws CancelledException if cancelled - */ - private boolean findSpecialTypeinfosAndVtables() throws CancelledException { - - class_type_info_vtable = findSpecialVtable("__cxxabiv1", "__class_type_info"); - - if (class_type_info_vtable == null) { - Msg.debug(this, - "***** __class_type_info vtable not found --> no classes without parents"); - } - else { - - Symbol class_type_info_symbol = - getSymbolInNamespaces("__cxxabiv1", "__class_type_info", "typeinfo"); - if (class_type_info_symbol == null) { - Msg.debug(this, - "__class_type_info typeinfo not found -- cannot continue gcc rtti processing"); - return false; - } - class_type_info = class_type_info_symbol.getAddress(); - - } - - 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"); - } - else { - Symbol si_class_type_info_symbol = - getSymbolInNamespaces("__cxxabiv1", "__si_class_type_info", "typeinfo"); - if (si_class_type_info_symbol == null) { - Msg.debug(this, - "__si_class_type_info typeinfo not found -- cannot continue gcc rtti processing"); - return false; - } - si_class_type_info = si_class_type_info_symbol.getAddress(); - } - - vmi_class_type_info_vtable = findSpecialVtable("__cxxabiv1", "__vmi_class_type_info"); - if (vmi_class_type_info_vtable == null) { - Msg.debug(this, "__vmi_class_type_info vtable not found --> no multi-parent classes"); - } - else { - Symbol vmi_class_type_info_symbol = - getSymbolInNamespaces("__cxxabiv1", "__vmi_class_type_info", "typeinfo"); - if (vmi_class_type_info_symbol == null) { - Msg.debug(this, - "__vmi_class_type_info typeinfo not found -- cannot continue gcc rtti processing"); - return false; - } - vmi_class_type_info = vmi_class_type_info_symbol.getAddress(); - } - - 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; - - } - // TODO: don't delete - its call is commented out waiting for more work above private List addMissingClasses(List subset, List newList, List classList) @@ -1467,15 +1473,17 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // find the special type info ref Address typeinfoAddress = findNextTypeinfoRef(vtableAddress); if (typeinfoAddress == null) { - Msg.debug(this, vtableAddress.toString() + " " + vtableNamespace.getName() + - " vtable has no typeinfo ref"); + if (DEBUG) { + Msg.debug(this, vtableAddress.toString() + " " + vtableNamespace.getName() + + " vtable has no typeinfo ref"); + } continue; } Address vftableAddress = extraUtils.getAddress(typeinfoAddress, defaultPointerSize); // no valid address here so continue if (vftableAddress == null) { - //TODO: print to see if any happen + addNoVftableClass(vtableNamespace); // if so should also add to no vftable class continue; } @@ -1493,12 +1501,21 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { /** * Method to check if given typeinfo is one of the three special ones - * @param typeinfoAddress the given typeinfo address + * @param address the given typeinfo address * @return true if it is a special one, false otherwise */ - private boolean isSpecialTypeinfo(Address typeinfoAddress) { - if (typeinfoAddress.equals(class_type_info) || typeinfoAddress.equals(si_class_type_info) || - typeinfoAddress.equals(vmi_class_type_info)) { + 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; @@ -1521,6 +1538,14 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { 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; + } + + // TODO: make sure it is a valid typeinfo + Namespace classNamespace = typeinfoSymbol.getParentNamespace(); @@ -1545,23 +1570,36 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { Address specialTypeinfoRef = extraUtils.getSingleReferencedAddress(typeinfoAddress); if (specialTypeinfoRef == null) { - Msg.debug(this, - "No special typeinfo reference found. Cannot process typeinfo struct at " + - typeinfoAddress.toString()); + if (DEBUG) { + Msg.debug(this, + "No special typeinfo reference found. Cannot process typeinfo struct at " + + typeinfoAddress.toString()); + } continue; } if (!isSpecialTypeinfo(specialTypeinfoRef)) { - continue; + // 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) // ??? it isn't clear whether these are always public or not - if (specialTypeinfoRef.equals(class_type_info)) { + if (specialTypeinfoRef.equals(class_type_info) || + specialTypeinfoRef.equals(class_type_info_vtable)) { // //TODO: make this a method - addGccNoInhClass - //nonInheritedClasses.add(recoveredClass); recoveredClass.setHasSingleInheritance(true); recoveredClass.setHasParentClass(false); recoveredClass.setInheritsVirtualAncestor(false); @@ -1572,8 +1610,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // per docs those on this list are // classes containing only a single, public, non-virtual base at offset zero // update: it isn't clear if never inherit virtual - may have found example - if (specialTypeinfoRef.equals(si_class_type_info)) { - // singleInheritedClasses.add(recoveredClass); + if (specialTypeinfoRef.equals(si_class_type_info) || + specialTypeinfoRef.equals(si_class_type_info_vtable)) { + // TODO: make this a method and pull the part out of add parents that handles the // single parent one recoveredClass.setHasSingleInheritance(true); @@ -1583,11 +1622,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { continue; } - if (specialTypeinfoRef.equals(vmi_class_type_info)) { + if (specialTypeinfoRef.equals(vmi_class_type_info) || + specialTypeinfoRef.equals(vmi_class_type_info_vtable)) { - // multiInheritedClasses.add(recoveredClass); recoveredClass.setHasMultipleInheritance(true); - recoveredClass.setHasParentClass(true); } } return recoveredClasses; @@ -1833,5 +1871,246 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { return false; } + /** + * 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. + * @param recoveredClasses List of classes + * @throws CancelledException when cancelled + * @throws Exception if issue creating data + */ + private void createAndApplyClassStructures(List recoveredClasses) + throws CancelledException, Exception { + + List listOfClasses = new ArrayList(recoveredClasses); + + Iterator recoveredClassIterator = recoveredClasses.iterator(); + + // first process all the classes with no parents + while (recoveredClassIterator.hasNext()) { + monitor.checkCanceled(); + + RecoveredClass recoveredClass = recoveredClassIterator.next(); + + if (recoveredClass.hasMultipleInheritance()) { + continue; + } + + if (recoveredClass.hasParentClass()) { + continue; + } + + if (!recoveredClass.hasVftable()) { + createClassStructureWhenNoParentOrVftable(recoveredClass); + listOfClasses.remove(recoveredClass); + continue; + } + + processDataTypes(recoveredClass); + listOfClasses.remove(recoveredClass); + + } + + // now process the classes that have all parents processed + // continue looping until all classes are processed + int numLoops = 0; + + while (!listOfClasses.isEmpty()) { + monitor.checkCanceled(); + + // put in stop gap measure in case some classes never get all + // parents processed for some reason + if (numLoops == 100) { + return; + } + numLoops++; + + recoveredClassIterator = recoveredClasses.iterator(); + while (recoveredClassIterator.hasNext()) { + + RecoveredClass recoveredClass = recoveredClassIterator.next(); + + monitor.checkCanceled(); + if (!listOfClasses.contains(recoveredClass)) { + continue; + } + + if (!allAncestorDataHasBeenCreated(recoveredClass)) { + continue; + } + + processDataTypes(recoveredClass); + listOfClasses.remove(recoveredClass); + + } + } + } + + /** + * 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 + */ + private void processDataTypes(RecoveredClass recoveredClass) + throws CancelledException, Exception { + + // can't handle gcc multi and/or virtual class data types yet + if (multiInheritedGccClasses.contains(recoveredClass) || + recoveredClass.inheritsVirtualAncestor()) { + return; + } + + // shouldn't happen if we get to this point since it should be all single or no inherited classes + // but check anyway + if (recoveredClass.getVftableAddresses().size() > 1) { + 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 + return; + } + + // create pointers to empty vftable structs so they can be added to the class data type + // then filled in later + Map vfPointerDataTypes = createEmptyVfTableStructs(recoveredClass); + + // create current class structure and add pointer to vftable, all parent member data strutures, and class member data structure + Structure classStruct = null; + + classStruct = createSimpleClassStructure(recoveredClass, vfPointerDataTypes); + + // TODO: check for DWARF -- if none add c/d/etc to class +// if (!isDWARFLoaded) { +// +// // Now that we have a class data type +// // name constructor and destructor functions and put into the class namespace +// addConstructorsToClassNamespace(recoveredClass, classStruct); +// addDestructorsToClassNamespace(recoveredClass); +// addNonThisDestructorsToClassNamespace(recoveredClass); +// addVbaseDestructorsToClassNamespace(recoveredClass); +// addVbtableToClassNamespace(recoveredClass); +// +// // add secondary label on functions with inlined constructors or destructors +// createInlinedConstructorComments(recoveredClass); +// createInlinedDestructorComments(recoveredClass); +// createIndeterminateInlineComments(recoveredClass); +// +// // add label on constructor destructor functions that could not be determined which were which +// createIndeterminateLabels(recoveredClass); +// } + + // This is done after the class structure is created and added to the dtmanager + // because if done before the class structures are created + // then empty classes will get auto-created in the wrong place + // when the vfunctions are put in the class + + fillInAndApplyVftableStructAndNameVfunctions(recoveredClass, vfPointerDataTypes); + + } + + private Structure createSimpleClassStructure(RecoveredClass recoveredClass, + Map vfPointerDataTypes) throws Exception { + + String className = recoveredClass.getName(); + + CategoryPath classPath = recoveredClass.getClassPath(); + + // 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 { + classStructure = recoveredClass.getComputedClassStructure(); + } + + int structLen = 0; + if (classStructure != null) { + structLen = addAlignment(classStructure.getLength()); + } + + Structure classStructureDataType = + new StructureDataType(classPath, className, structLen, dataTypeManager); + + List parentList = recoveredClass.getParentList(); + // shouldn't happen but check anyway + if (parentList.size() > 1) { + return classStructureDataType; + } + + // if no inheritance - add pointer to class vftable structure + if (nonInheritedGccClasses.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 + Address vftableAddress = recoveredClass.getVftableAddresses().get(0); + DataType classVftablePointer = vfPointerDataTypes.get(vftableAddress); + + // simple case the offset for vftablePtr is 0 + if (structUtils.canAdd(classStructureDataType, 0, classVftablePointer.getLength(), + monitor)) { + classStructureDataType = structUtils.addDataTypeToStructure(classStructureDataType, + 0, classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor); + + } + } + // if single inheritance put parent and data + else if (singleInheritedGccClasses.contains(recoveredClass)) { + + RecoveredClass baseClass = parentList.get(0); + Structure baseClassStructure = getClassStructureFromDataTypeManager(baseClass); + + // simple case - base class at offset 0 + if (structUtils.canAdd(classStructureDataType, 0, baseClassStructure.getLength(), + monitor)) { + classStructureDataType = structUtils.addDataTypeToStructure(classStructureDataType, + 0, baseClassStructure, baseClassStructure.getName(), monitor); + } + } + + // figure out class data, if any, create it and add to class structure + int dataOffset = getDataOffset(recoveredClass, classStructureDataType); + int dataLen = UNKNOWN; + if (dataOffset != NONE) { + dataLen = structUtils.getNumberOfUndefinedsStartingAtOffset(classStructureDataType, + dataOffset, monitor); + } + + if (dataLen != UNKNOWN && dataLen > 0) { + + Structure recoveredClassDataStruct = createClassMemberDataStructure(recoveredClass, + classStructureDataType, dataLen, dataOffset); + + if (recoveredClassDataStruct != null) { + classStructureDataType = structUtils.addDataTypeToStructure(classStructureDataType, + dataOffset, recoveredClassDataStruct, "data", monitor); + } + + } + + if (classStructureDataType.getNumComponents() == classStructureDataType.getNumDefinedComponents()) { + classStructureDataType.setPackingEnabled(true); + } + + classStructureDataType.setDescription(createParentStringBuffer(recoveredClass).toString()); + + classStructureDataType = (Structure) dataTypeManager.addDataType(classStructureDataType, + DataTypeConflictHandler.DEFAULT_HANDLER); + + return classStructureDataType; + } + + private boolean hasExternalBlock() { + MemoryBlock externalBlock = program.getMemory().getBlock("EXTERNAL"); + if (externalBlock == null) { + return false; + } + return true; + } + } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java index 5f75f288c6..8cef4518dd 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java @@ -485,7 +485,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { for (int i = 0; i < numBaseClasses; i++) { monitor.checkCanceled(); - + //TODO: extraUtils.getReferencedAddress(address, getIboIf64bit); Address baseClassDescriptorAddress = getReferencedAddress(address.add(i * 4)); Data baseClassDescriptor = extraUtils.getDataAt(baseClassDescriptorAddress); @@ -572,6 +572,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { private Address createClassHierarchyDescriptor(Address address, Namespace classNamespace) throws CancelledException, MemoryAccessException, InvalidInputException, Exception { + //TODO: extraUtils.getReferencedAddress(address, getIboIf64bit); Address classHierarchyDescriptorAddress = getReferencedAddress(address); Data classHierarchyStructure = extraUtils.getDataAt(classHierarchyDescriptorAddress); @@ -652,6 +653,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { int numBaseClasses = extraUtils.getInt(classHierarchyDescriptorAddress.add(8)); + //TODO: extraUtils.getReferencedAddress(address, getIboIf64bit); Address baseClassArrayAddress = getReferencedAddress(classHierarchyDescriptorAddress.add(12)); @@ -1295,8 +1297,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { */ private void setClassInheritanceType(RecoveredClass recoveredClass, int inheritanceType) { - // TODO: update the single virtual case from here too - may need to update class - // TODO: ?? add multi-repeate base inh flag? do I care other than to give info to user? + // TODO: add multi-repeated base inh flag? if ((inheritanceType & CHD_MULTINH) == 0) { recoveredClass.setHasSingleInheritance(true); @@ -1305,11 +1306,11 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { if ((inheritanceType & CHD_VIRTINH) == 0) { recoveredClass.setInheritsVirtualAncestor(false); } -// else { -// // TODO: might have to update the single virt inh here -// println("Flag indicates single inheritance virtual ancestor for class " + -// recoveredClass.getName()); -// } + // Flag indicates single inheritance virtual ancestor for class " + + // recoveredClass.getName()); + else { + recoveredClass.setInheritsVirtualAncestor(true); + } } else { recoveredClass.setHasSingleInheritance(false); @@ -1317,10 +1318,11 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { if ((inheritanceType & CHD_VIRTINH) == 0) { recoveredClass.setHasMultipleVirtualInheritance(false); } + + // Flag indicates multiple inheritance virtual ancestor for class " + + // recoveredClass.getName()); else { recoveredClass.setHasMultipleVirtualInheritance(true); -// println("Flag indicates multiple inheritance virtual ancestor for class " + -// recoveredClass.getName()); } } //TODO: CHD_AMBIGUOUS = 0x00000004; diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassUtils.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassUtils.java index 7558bfecbe..ed0b85d116 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassUtils.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassUtils.java @@ -41,6 +41,7 @@ import ghidra.app.plugin.core.decompile.actions.FillOutStructureCmd; import ghidra.app.plugin.core.decompile.actions.FillOutStructureCmd.OffsetPcodeOpPair; import ghidra.app.plugin.core.navigation.locationreferences.LocationReference; import ghidra.app.plugin.core.navigation.locationreferences.ReferenceUtils; +import ghidra.app.util.NamespaceUtils; import ghidra.framework.plugintool.PluginTool; import ghidra.program.database.data.DataTypeUtilities; import ghidra.program.flatapi.FlatProgramAPI; @@ -85,6 +86,8 @@ public class RecoveredClassUtils { private static int MIN_OPERATOR_NEW_REFS = 10; + private static final boolean DEBUG = false; + private Map vftableToClassMap = new HashMap(); // map from vftable references to the vftables they point to @@ -1012,7 +1015,9 @@ public class RecoveredClassUtils { List functionClasses = getClasses(function); if (functionClasses == null) { - Msg.debug(this, "no function to class map for " + function.getEntryPoint()); + if (DEBUG) { + Msg.debug(this, "no function to class map for " + function.getEntryPoint()); + } return true; } Iterator functionClassesIterator = functionClasses.iterator(); @@ -1098,8 +1103,10 @@ public class RecoveredClassUtils { List
vftableReferenceList = getVftableReferences(function); if (vftableReferenceList == null) { - Msg.debug(this, "In update maps: function to class map doesn't exist for " + - function.getEntryPoint().toString()); + if (DEBUG) { + Msg.debug(this, "In update maps: function to class map doesn't exist for " + + function.getEntryPoint().toString()); + } return; } Collections.sort(vftableReferenceList); @@ -1113,10 +1120,11 @@ public class RecoveredClassUtils { RecoveredClass vftableClass = getVftableClass(vftableAddress); if (!vftableClass.equals(recoveredClass)) { - Msg.debug(this, - "updating struct for " + recoveredClass.getName() + + if (DEBUG) { + Msg.debug(this, "updating struct for " + recoveredClass.getName() + " but first vftable in function " + function.getEntryPoint().toString() + " is in class " + vftableClass.getName()); + } return; } @@ -1196,8 +1204,10 @@ public class RecoveredClassUtils { return; } - Msg.debug(this, "Could not find variable pointing to vftable in " + - function.getEntryPoint().toString()); + if (DEBUG) { + Msg.debug(this, "Could not find variable pointing to vftable in " + + function.getEntryPoint().toString()); + } } @@ -2046,8 +2056,10 @@ public class RecoveredClassUtils { } if (vftableAddresses.size() != classOffsetToVftableMap.size()) { - Msg.debug(this, recoveredClass.getName() + " has " + vftableAddresses.size() + - " vftables but " + classOffsetToVftableMap.size() + " offset to vftable maps"); + if (DEBUG) { + Msg.debug(this, recoveredClass.getName() + " has " + vftableAddresses.size() + + " vftables but " + classOffsetToVftableMap.size() + " offset to vftable maps"); + } } List offsetList = new ArrayList(classOffsetToVftableMap.keySet()); @@ -2717,20 +2729,19 @@ public class RecoveredClassUtils { // Get class name from class vftable is in Namespace vftableNamespace = vftableSymbol.getParentNamespace(); if (vftableNamespace.equals(globalNamespace)) { - Msg.debug(this, - "vftable is in the global namespace, ie not in a class namespace, so cannot process"); + if (DEBUG) { + Msg.debug(this, + "vftable is in the global namespace, ie not in a class namespace, so cannot process"); + } continue; } - SymbolType namespaceType = vftableNamespace.getSymbol().getSymbolType(); - if (namespaceType != SymbolType.CLASS) { - // if it is a namespace but not a class we need to promote it to a class namespace - if (namespaceType == SymbolType.NAMESPACE) { - - //vftableNamespace = promoteToClassNamespace(vftableNamespace); - - // else just leave the old one as a namepace - + // promote any non-class namespaces in the vftableNamespace path to class namespaces + boolean success = promoteNamespaces(vftableNamespace.getSymbol()); + if (!success) { + if (DEBUG) { + Msg.debug(this, "Unable to promote all non-class namespaces for " + + vftableNamespace.getName(true)); } } @@ -2808,6 +2819,60 @@ public class RecoveredClassUtils { return recoveredClasses; } + private boolean promoteNamespaces(Symbol symbol) throws CancelledException { + + Namespace namespace = symbol.getParentNamespace(); + while (!namespace.isGlobal()) { + + monitor.checkCanceled(); + SymbolType namespaceType = namespace.getSymbol().getSymbolType(); + if (namespaceType != SymbolType.CLASS) { + // if it is a namespace but not a class we need to promote it to a class namespace + if (namespaceType == SymbolType.NAMESPACE) { + namespace = promoteToClassNamespace(namespace); + if (namespace == null) { + return false; + } + if (DEBUG) { + Msg.debug(this, + "Promoted namespace " + namespace.getName() + " to a class namespace"); + } + } + } + else { + namespace = namespace.getParentNamespace(); + } + } + return true; + } + + /** + * Method to promote the namespace is a class namespace. + * @return true if namespace is (now) a class namespace or false if it could not be promoted. + */ + private Namespace promoteToClassNamespace(Namespace namespace) { + + try { + Namespace newClass = NamespaceUtils.convertNamespaceToClass(namespace); + + SymbolType symbolType = newClass.getSymbol().getSymbolType(); + if (symbolType == SymbolType.CLASS) { + return newClass; + } + if (DEBUG) { + Msg.debug(this, + "Could not promote " + namespace.getName() + " to a class namespace"); + } + return null; + } + catch (InvalidInputException e) { + + Msg.debug(this, "Could not promote " + namespace.getName() + + " to a class namespace because " + e.getMessage()); + return null; + } + } + /** * Method to create mapping to possible constructor/destructor functions * @param referencesToVftable list of references to a particular vftable @@ -3397,8 +3462,10 @@ public class RecoveredClassUtils { if (symbolsByNameAtAddress.size() == 0) { AddLabelCmd lcmd = new AddLabelCmd(address, name, namespace, SourceType.ANALYSIS); if (!lcmd.applyTo(program)) { - Msg.debug(this, - "ERROR: Could not add new symbol " + name + " to " + address.toString()); + if (DEBUG) { + Msg.debug(this, + "ERROR: Could not add new symbol " + name + " to " + address.toString()); + } } } //put the same name one in the namespace @@ -3491,8 +3558,10 @@ public class RecoveredClassUtils { AddLabelCmd lcmd = new AddLabelCmd(function.getEntryPoint(), name, namespace, SourceType.ANALYSIS); if (!lcmd.applyTo(program)) { - Msg.debug(this, "ERROR: Could not add new function label " + name + " to " + - function.getEntryPoint().toString()); + if (DEBUG) { + Msg.debug(this, "ERROR: Could not add new function label " + name + " to " + + function.getEntryPoint().toString()); + } return; } @@ -3501,8 +3570,10 @@ public class RecoveredClassUtils { SetLabelPrimaryCmd scmd = new SetLabelPrimaryCmd(function.getEntryPoint(), name, namespace); if (!scmd.applyTo(program)) { - Msg.debug(this, "ERROR: Could not make function label " + name + - " primary at " + function.getEntryPoint().toString()); + if (DEBUG) { + Msg.debug(this, "ERROR: Could not make function label " + name + + " primary at " + function.getEntryPoint().toString()); + } } } } @@ -3756,8 +3827,10 @@ public class RecoveredClassUtils { } else { - Msg.debug(this, "ERROR: " + function.getEntryPoint().toString() + - " Could not replace parameter " + i + " with undefined pointer."); + if (DEBUG) { + Msg.debug(this, "ERROR: " + function.getEntryPoint().toString() + + " Could not replace parameter " + i + " with undefined pointer."); + } } } } @@ -4818,9 +4891,11 @@ public class RecoveredClassUtils { //TODO: remove after testing if (!classVftableRef.equals(otherWayRef)) { - Msg.debug(this, recoveredClass.getName() + " function " + - destructorFunction.getEntryPoint().toString() + " first ref: " + - classVftableRef.toString() + " other way ref: " + otherWayRef.toString()); + if (DEBUG) { + Msg.debug(this, recoveredClass.getName() + " function " + + destructorFunction.getEntryPoint().toString() + " first ref: " + + classVftableRef.toString() + " other way ref: " + otherWayRef.toString()); + } } String markupString = classNamespace.getName(true) + "::~" + className; @@ -4857,10 +4932,12 @@ public class RecoveredClassUtils { } //TODO: remove after testing if (!classVftableRef.equals(otherWayRef)) { + if (DEBUG) { Msg.debug(this, recoveredClass.getName() + " function " + functionContainingInline.getEntryPoint().toString() + " first ref: " + classVftableRef.toString() + " other way ref: " + otherWayRef.toString()); + } } String markupString = "inlined constructor or destructor (approx location) for " + @@ -5070,11 +5147,12 @@ public class RecoveredClassUtils { return; } if (!vftableReference.equals(otherWayRef)) { - Msg.debug(this, - recoveredClass.getName() + " function " + + if (DEBUG) { + Msg.debug(this, recoveredClass.getName() + " function " + virtualFunction.getEntryPoint().toString() + " first ref: " + vftableReference.toString() + " other way ref (with ances): " + otherWayRef.toString()); + } } List possibleParentDestructors = getPossibleParentDestructors(virtualFunction); @@ -5108,7 +5186,9 @@ public class RecoveredClassUtils { recoveredClass.addDeletingDestructor(virtualFunction); if (recoveredClass.getDestructorList().contains(virtualFunction)) { - Msg.debug(this, "Already created vfunction as a destructor"); + if (DEBUG) { + Msg.debug(this, "Already created vfunction as a destructor"); + } } recoveredClass.removeFromConstructorDestructorList(virtualFunction); recoveredClass.removeIndeterminateConstructorOrDestructor(virtualFunction); @@ -6053,8 +6133,10 @@ public class RecoveredClassUtils { Function operatorDeleteFunction = findOperatorDeleteUsingKnownDeletingDestructors(recoveredClasses); if (operatorDeleteFunction == null) { - Msg.debug(this, - "Could not find operator delete function. Cannot process more deleting destructors."); + if (DEBUG) { + Msg.debug(this, + "Could not find operator delete function. Cannot process more deleting destructors."); + } return; } @@ -6645,7 +6727,9 @@ public class RecoveredClassUtils { } // if they ever don't match return else if (!possiblePureCall.equals(sameFunction)) { - Msg.debug(this, "Could not identify pure call. "); + if (DEBUG) { + Msg.debug(this, "Could not identify pure call. "); + } return; } }