GP-5831 Added a few speed improvements to the RecoverClassesFromRTTIScript.

This commit is contained in:
ghidra007
2025-12-03 05:05:17 -05:00
committed by Ryan Kurtz
parent f901a1bb4a
commit c5beedac5a
5 changed files with 339 additions and 113 deletions
@@ -116,7 +116,8 @@ public class DecompilerScriptUtils {
if (decompRes == null || decompRes.getHighFunction() == null || if (decompRes == null || decompRes.getHighFunction() == null ||
decompRes.getHighFunction().getFunctionPrototype() == null) { decompRes.getHighFunction().getFunctionPrototype() == null) {
Msg.debug(this, "Couldn't commit params - null high function"); Msg.debug(this, "Couldn't commit params - null high function " +
function.getEntryPoint().toString());
return; return;
} }
@@ -125,11 +126,13 @@ public class DecompilerScriptUtils {
ReturnCommitOption.COMMIT, SourceType.ANALYSIS); ReturnCommitOption.COMMIT, SourceType.ANALYSIS);
} }
catch (DuplicateNameException e) { catch (DuplicateNameException e) {
Msg.debug(this, "Couldn't commit params " + e); Msg.debug(this,
"Couldn't commit params for " + function.getEntryPoint().toString() + " " + e);
return; return;
} }
catch (InvalidInputException e) { catch (InvalidInputException e) {
Msg.debug(this, "Couldn't commit params " + e); Msg.debug(this,
"Couldn't commit params for " + function.getEntryPoint().toString() + " " + e);
return; return;
} }
} }
@@ -324,6 +324,12 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
functionAddress = functionAddress.getNewAddress(longValue); functionAddress = functionAddress.getNewAddress(longValue);
} }
// skip anything that is data - this could get passed in if it is an external ptr to a function
Data data = getDataAt(functionAddress);
if (data != null) {
return null;
}
Function function = getFunctionAt(functionAddress); Function function = getFunctionAt(functionAddress);
if (function == null) { if (function == null) {
// try to create function // try to create function
@@ -1002,6 +1008,9 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
* @return the referenced function or null if no function is referenced * @return the referenced function or null if no function is referenced
* @throws CancelledException if cancelled * @throws CancelledException if cancelled
*/ */
//TODO: this is same as getReferencedFunction at line 313 except for the thunked function
// argument but is missing the lowBit code stuff - combine both and replace uses to use the
// one merged version - this one has loop and the other just works if one ref
public Function getReferencedFunction(Address address, boolean getThunkedFunction) public Function getReferencedFunction(Address address, boolean getThunkedFunction)
throws CancelledException { throws CancelledException {
@@ -1020,6 +1029,19 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
continue; continue;
} }
Register lowBitCodeMode = currentProgram.getRegister("LowBitCodeMode");
if (lowBitCodeMode != null) {
long longValue = referencedAddress.getOffset();
longValue = longValue & ~0x1;
referencedAddress = referencedAddress.getNewAddress(longValue);
}
// skip anything that is data - this could get passed in if it is an external ptr to a function
Data data = getDataAt(referencedAddress);
if (data != null) {
continue;
}
Function function = getFunctionAt(referencedAddress); Function function = getFunctionAt(referencedAddress);
if (function == null) { if (function == null) {
@@ -1197,7 +1219,7 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
} }
/** /**
* Method to generate unique shorted names for classes with templates * Method to generate unique shortened names for classes with templates
* @param recoveredClasses the list of classes in the program * @param recoveredClasses the list of classes in the program
* @throws CancelledException if cancelled * @throws CancelledException if cancelled
*/ */
@@ -167,15 +167,16 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
// using all the information found above, create the class structures, add the constructor, // using all the information found above, create the class structures, add the constructor,
// destructor, vfunctions to class which finds the appropriate class structure and assigns // destructor, vfunctions to class which finds the appropriate class structure and assigns
// to "this" param // to "this" param
monitor.setMessage("Creating class data types and applying class structures"); monitor.setMessage("Figuring out class data members...");
figureOutClassDataMembers(recoveredClasses); figureOutClassDataMembers(recoveredClasses);
if (USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS) { if (USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS) {
extendedFlatAPI.createShortenedTemplateNamesForClasses(recoveredClasses); extendedFlatAPI.createShortenedTemplateNamesForClasses(recoveredClasses);
} }
monitor.setMessage("Creating class data types and applying class structures...");
createAndApplyClassStructures(recoveredClasses); createAndApplyClassStructures(recoveredClasses);
monitor.setMessage("Finishing up...");
// fix purecall vfunction definitions // fix purecall vfunction definitions
fixupPurecallFunctionDefs(); fixupPurecallFunctionDefs();
@@ -1299,12 +1300,15 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
// lists to remove functions that are also on vfunction lists // lists to remove functions that are also on vfunction lists
trimConstructorDestructorLists(recoveredClasses, allVftables); trimConstructorDestructorLists(recoveredClasses, allVftables);
monitor.setMessage("... determining operator_delete and new functions");
determineOperatorDeleteAndNewFunctions(allVftables); determineOperatorDeleteAndNewFunctions(allVftables);
// find deleting destructors // find deleting destructors
monitor.setMessage("... finding deleting destructors");
findDeletingDestructors(recoveredClasses, allVftables); findDeletingDestructors(recoveredClasses, allVftables);
// use atexit param list to find more destructors // use atexit param list to find more destructors
monitor.setMessage("... finding destructors using atexit calls");
findDestructorsUsingAtexitCalledFunctions(recoveredClasses); findDestructorsUsingAtexitCalledFunctions(recoveredClasses);
// figure out which are inlined and put on separate list to be processed later // figure out which are inlined and put on separate list to be processed later
@@ -1312,33 +1316,43 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
// figure out which member functions are constructors and which are destructors // 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
monitor.setMessage("... processing constructors and destructors using call order");
processRegularConstructorsAndDestructorsUsingCallOrder(recoveredClasses); processRegularConstructorsAndDestructorsUsingCallOrder(recoveredClasses);
// determine which of the inlines are constructors and which are destructors // determine which of the inlines are constructors and which are destructors
monitor.setMessage("... processing inlineds");
processInlinedConstructorsAndDestructors(recoveredClasses); processInlinedConstructorsAndDestructors(recoveredClasses);
monitor.setMessage("... finding more constructors and destructors");
findConstructorsAndDestructorsUsingAncestorClassFunctions(recoveredClasses); findConstructorsAndDestructorsUsingAncestorClassFunctions(recoveredClasses);
monitor.setMessage("... finding more inlines");
findInlineConstructorsAndDestructorsUsingRelatedClassFunctions(recoveredClasses); 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 // ones that could not be determined in earlier stages
monitor.setMessage("... processing remaining indeterminate constructors and destructors");
processRemainingIndeterminateConstructorsAndDestructors(recoveredClasses); processRemainingIndeterminateConstructorsAndDestructors(recoveredClasses);
// use the known constructors and known vfunctions to figure out basic clone functions // use the known constructors and known vfunctions to figure out basic clone functions
monitor.setMessage("... finding basic clones");
findBasicCloneFunctions(recoveredClasses); findBasicCloneFunctions(recoveredClasses);
// This has to be here. It needs all the info from the previously run methods to do this. // 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 // 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 // first block, and call non-parent constructors and non operator new before the vftable ref
monitor.setMessage("... finding more inlined constructors");
findMoreInlinedConstructors(recoveredClasses); findMoreInlinedConstructors(recoveredClasses);
monitor.setMessage("... finding destructors with no params");
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 // destructor)to find the purecall function
monitor.setMessage("... identifying pure virtual function");
identifyPureVirtualFunction(recoveredClasses); identifyPureVirtualFunction(recoveredClasses);
monitor.setMessage("... finding real vbase functions");
findRealVBaseFunctions(recoveredClasses); findRealVBaseFunctions(recoveredClasses);
// make constructors and destructors _thiscalls // make constructors and destructors _thiscalls
@@ -1905,8 +1919,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
parentOrderMap = new HashMap<Integer, RecoveredClass>(); parentOrderMap = new HashMap<Integer, RecoveredClass>();
Map<Address, RecoveredClass> referenceToParentMap = Map<Address, ReferencedClassObject> referenceToParentMap =
getReferenceToClassMap(recoveredClass, function); getReferenceToReferencedObjectsMap(recoveredClass, function);
Map<Address, RecoveredClass> allowedReferncesToParentMap = Map<Address, RecoveredClass> allowedReferncesToParentMap =
new HashMap<Address, RecoveredClass>(); new HashMap<Address, RecoveredClass>();
@@ -1933,8 +1947,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
recoveredClass.getVftableAddresses().contains(possibleVftable)) { recoveredClass.getVftableAddresses().contains(possibleVftable)) {
continue; continue;
} }
ReferencedClassObject referencedClassObject =
RecoveredClass ancestorClass = referenceToParentMap.get(classReferenceAddress); referenceToParentMap.get(classReferenceAddress);
RecoveredClass ancestorClass = referencedClassObject.getContainingClass();
if (allowedAncestors.contains(ancestorClass)) { if (allowedAncestors.contains(ancestorClass)) {
allowedReferncesToParentMap.put(classReferenceAddress, ancestorClass); allowedReferncesToParentMap.put(classReferenceAddress, ancestorClass);
} }
@@ -1955,7 +1970,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
// iterate over the ordered parents and add the order to the parent map // iterate over the ordered parents and add the order to the parent map
for (Address refAddress : parentReferences) { for (Address refAddress : parentReferences) {
monitor.checkCancelled(); monitor.checkCancelled();
RecoveredClass parentClass = referenceToParentMap.get(refAddress); ReferencedClassObject referencedClassObject = referenceToParentMap.get(refAddress);
RecoveredClass parentClass = referencedClassObject.getContainingClass();
parentOrderMap.put(order, parentClass); parentOrderMap.put(order, parentClass);
order++; order++;
} }
@@ -2077,16 +2093,12 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
private void createAndApplyClassStructures(List<RecoveredClass> recoveredClasses) private void createAndApplyClassStructures(List<RecoveredClass> recoveredClasses)
throws CancelledException, Exception { throws CancelledException, Exception {
List<RecoveredClass> listOfClasses = new ArrayList<RecoveredClass>(recoveredClasses); List<RecoveredClass> processedClasses = new ArrayList<>();
Iterator<RecoveredClass> recoveredClassIterator = recoveredClasses.iterator();
// first process all the classes with no parents // first process all the classes with no parents
while (recoveredClassIterator.hasNext()) { for (RecoveredClass recoveredClass : recoveredClasses) {
monitor.checkCancelled(); monitor.checkCancelled();
RecoveredClass recoveredClass = recoveredClassIterator.next();
if (recoveredClass.hasMultipleInheritance()) { if (recoveredClass.hasMultipleInheritance()) {
continue; continue;
} }
@@ -2097,20 +2109,19 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
if (!recoveredClass.hasVftable()) { if (!recoveredClass.hasVftable()) {
createClassStructureWhenNoParentOrVftable(recoveredClass); createClassStructureWhenNoParentOrVftable(recoveredClass);
listOfClasses.remove(recoveredClass); processedClasses.add(recoveredClass);
continue; continue;
} }
processDataTypes(recoveredClass); processDataTypes(recoveredClass);
listOfClasses.remove(recoveredClass); processedClasses.add(recoveredClass);
} }
// now process the classes that have all parents processed // now process the classes that have all parents processed
// continue looping until all classes are processed // continue looping until all classes are processed
int numLoops = 0; int numLoops = 0;
while (!listOfClasses.isEmpty()) { while (processedClasses.size() < recoveredClasses.size()) {
monitor.checkCancelled(); monitor.checkCancelled();
// put in stop gap measure in case some classes never get all // put in stop gap measure in case some classes never get all
@@ -2120,13 +2131,10 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
} }
numLoops++; numLoops++;
recoveredClassIterator = recoveredClasses.iterator(); for (RecoveredClass recoveredClass : recoveredClasses) {
while (recoveredClassIterator.hasNext()) {
RecoveredClass recoveredClass = recoveredClassIterator.next();
monitor.checkCancelled(); monitor.checkCancelled();
if (!listOfClasses.contains(recoveredClass)) {
if (processedClasses.contains(recoveredClass)) {
continue; continue;
} }
@@ -2135,8 +2143,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
} }
processDataTypes(recoveredClass); processDataTypes(recoveredClass);
listOfClasses.remove(recoveredClass); processedClasses.add(recoveredClass);
} }
} }
} }
@@ -2673,11 +2680,10 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
continue; continue;
} }
if (numAddressRanges == 2) { if (numAddressRanges == 2) {
// else fixup split dd function // else possible split dd function - try to split and created second function
// if it is one
Function scalarDeletingDestructor = createSplitDeletingDestructorFunction(body); Function scalarDeletingDestructor = createSplitDeletingDestructorFunction(body);
if (scalarDeletingDestructor == null) { if (scalarDeletingDestructor == null) {
Msg.debug(this, "Could not fixup split deleting destructor function: " +
function.getEntryPoint());
continue; continue;
} }
fixupSplitDeletingDestructorSymbols(function, scalarDeletingDestructor); fixupSplitDeletingDestructorSymbols(function, scalarDeletingDestructor);
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -96,7 +96,6 @@ public class RecoveredClass {
TaskMonitor monitor = TaskMonitor.DUMMY; TaskMonitor monitor = TaskMonitor.DUMMY;
RecoveredClass(String name, CategoryPath classPath, Namespace classNamespace, RecoveredClass(String name, CategoryPath classPath, Namespace classNamespace,
DataTypeManager dataTypeManager) { DataTypeManager dataTypeManager) {
this.name = name; this.name = name;
@@ -519,19 +518,19 @@ public class RecoveredClass {
// if the new component is a non-empty structure, check to see if the current // if the new component is a non-empty structure, check to see if the current
// structure has undefined or equivalent components and replace with new struct if so // structure has undefined or equivalent components and replace with new struct if so
if (newComponentDataType instanceof Structure) { if (newComponentDataType instanceof Structure) {
// if new component is any empty placeholder structure AND if the existing component // if new component is any empty placeholder structure AND if the existing component
// is undefined then replace with undefined1 dt // is undefined then replace with undefined1 dt
if (newComponentDataType.isNotYetDefined()) { if (newComponentDataType.isNotYetDefined()) {
if (Undefined.isUndefined(currentComponentDataType)) { if (Undefined.isUndefined(currentComponentDataType)) {
computedClassStructure.replaceAtOffset(offset, new Undefined1DataType(), 1, computedClassStructure.replaceAtOffset(offset, new Undefined1DataType(), 1,
fieldName, comment); fieldName, comment);
} }
continue; continue;
} }
if (EditStructureUtils.hasReplaceableComponentsAtOffset(computedClassStructure, if (EditStructureUtils.hasReplaceableComponentsAtOffset(computedClassStructure,
offset, (Structure)newComponentDataType, monitor)) { offset, (Structure) newComponentDataType, monitor)) {
boolean successfulClear = boolean successfulClear =
EditStructureUtils.clearLengthAtOffset(computedClassStructure, offset, EditStructureUtils.clearLengthAtOffset(computedClassStructure, offset,
length, monitor); length, monitor);
@@ -675,4 +674,3 @@ public class RecoveredClass {
return shortenedTemplateName; return shortenedTemplateName;
} }
} }
File diff suppressed because it is too large Load Diff