mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-01-09 22:17:55 -05:00
GP-5831 Added a few speed improvements to the RecoverClassesFromRTTIScript.
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -141,6 +141,15 @@ public class RecoveredClassHelper {
|
|||||||
|
|
||||||
public HashMap<Address, Set<Function>> allVfunctions = new HashMap<>();
|
public HashMap<Address, Set<Function>> allVfunctions = new HashMap<>();
|
||||||
|
|
||||||
|
public HashMap<Function, Map<Address, Function>> functionCallMapFollowThunks =
|
||||||
|
new HashMap<>();
|
||||||
|
public HashMap<Function, Map<Address, Function>> functionCallMapDontFollowThunks =
|
||||||
|
new HashMap<>();
|
||||||
|
|
||||||
|
public HashMap<Address, ReferencedClassObject> referencedObjectMap = new HashMap<>();
|
||||||
|
public HashMap<Function, HashMap<Address, ReferencedClassObject>> functionReferenceMap =
|
||||||
|
new HashMap<>();
|
||||||
|
|
||||||
public RecoveredClassHelper(Program program, ServiceProvider serviceProvider,
|
public RecoveredClassHelper(Program program, ServiceProvider serviceProvider,
|
||||||
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
|
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
|
||||||
boolean nameVunctions, boolean makeVfunctionsThisCalls, TaskMonitor monitor)
|
boolean nameVunctions, boolean makeVfunctionsThisCalls, TaskMonitor monitor)
|
||||||
@@ -416,16 +425,30 @@ public class RecoveredClassHelper {
|
|||||||
* @param function the given function
|
* @param function the given function
|
||||||
* @param getThunkedFunction if true, use the thunked function in the map, if false use the
|
* @param getThunkedFunction if true, use the thunked function in the map, if false use the
|
||||||
* directly called function from the calling function even if it is a thunk
|
* directly called function from the calling function even if it is a thunk
|
||||||
* @param visited the set of function entry point addresses already processed
|
|
||||||
* @return a map of the given functions calling addresses to the called functions
|
* @return a map of the given functions calling addresses to the called functions
|
||||||
* @throws CancelledException if cancelled
|
* @throws CancelledException if cancelled
|
||||||
*/
|
*/
|
||||||
public Map<Address, Function> getFunctionCallMap(Function function, boolean getThunkedFunction,
|
public Map<Address, Function> getFunctionCallMap(Function function, boolean getThunkedFunction)
|
||||||
Set<Address> visited)
|
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
|
|
||||||
visited.add(function.getEntryPoint());
|
Map<Address, Function> functionCallMap;
|
||||||
Map<Address, Function> functionCallMap = new HashMap<Address, Function>();
|
|
||||||
|
if (getThunkedFunction) {
|
||||||
|
functionCallMap = functionCallMapFollowThunks.get(function);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
functionCallMap = functionCallMapDontFollowThunks.get(function);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (functionCallMap != null) {
|
||||||
|
return functionCallMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// initializing here not above because checking for empty map with the null
|
||||||
|
// wouldn't be correct because the below could generate an empty map if there are no
|
||||||
|
// calls at all. The above map check/return needs to distinguish between the not in map
|
||||||
|
// case and the already processed empty map case
|
||||||
|
functionCallMap = new HashMap<Address, Function>();
|
||||||
|
|
||||||
InstructionIterator instructions =
|
InstructionIterator instructions =
|
||||||
function.getProgram().getListing().getInstructions(function.getBody(), true);
|
function.getProgram().getListing().getInstructions(function.getBody(), true);
|
||||||
@@ -442,8 +465,14 @@ public class RecoveredClassHelper {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (calledFunction.isExternal()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// include the null functions in map so things using map can get accurate count
|
// include the null functions in map so things using map can get accurate count
|
||||||
// of number of CALL instructions even if the call reg type
|
// of number of CALL instructions even if the call reg type
|
||||||
|
//TODO: the above continue is preventing the nulls and exts here - do we want this?
|
||||||
|
// or do we want another map/option?
|
||||||
functionCallMap.put(instruction.getMinAddress(), calledFunction);
|
functionCallMap.put(instruction.getMinAddress(), calledFunction);
|
||||||
}
|
}
|
||||||
if (instruction.getFlowOverride().equals(FlowOverride.CALL_RETURN)) {
|
if (instruction.getFlowOverride().equals(FlowOverride.CALL_RETURN)) {
|
||||||
@@ -454,10 +483,9 @@ public class RecoveredClassHelper {
|
|||||||
Address functionAddress = reference.getFromAddress();
|
Address functionAddress = reference.getFromAddress();
|
||||||
Function secondHalfOfFunction =
|
Function secondHalfOfFunction =
|
||||||
extendedFlatAPI.getReferencedFunction(functionAddress);
|
extendedFlatAPI.getReferencedFunction(functionAddress);
|
||||||
if (secondHalfOfFunction != null &&
|
if (secondHalfOfFunction != null) {
|
||||||
!visited.contains(secondHalfOfFunction.getEntryPoint())) {
|
|
||||||
Map<Address, Function> functionCallMap2 =
|
Map<Address, Function> functionCallMap2 =
|
||||||
getFunctionCallMap(secondHalfOfFunction, false, visited);
|
getFunctionCallMap(secondHalfOfFunction, false);
|
||||||
for (Address addr : functionCallMap2.keySet()) {
|
for (Address addr : functionCallMap2.keySet()) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
functionCallMap.put(addr, functionCallMap2.get(addr));
|
functionCallMap.put(addr, functionCallMap2.get(addr));
|
||||||
@@ -466,12 +494,14 @@ public class RecoveredClassHelper {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return functionCallMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<Address, Function> getFunctionCallMap(Function function, boolean getThunkedFunction)
|
if (getThunkedFunction) {
|
||||||
throws CancelledException {
|
functionCallMapFollowThunks.put(function, functionCallMap);
|
||||||
return getFunctionCallMap(function, getThunkedFunction, new HashSet<>());
|
}
|
||||||
|
else {
|
||||||
|
functionCallMapDontFollowThunks.put(function, functionCallMap);
|
||||||
|
}
|
||||||
|
return functionCallMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateNamespaceToClassMap(Namespace namespace, RecoveredClass recoveredClass) {
|
public void updateNamespaceToClassMap(Namespace namespace, RecoveredClass recoveredClass) {
|
||||||
@@ -714,19 +744,26 @@ public class RecoveredClassHelper {
|
|||||||
public List<Address> getSortedListOfAncestorRefsInFunction(Function function,
|
public List<Address> getSortedListOfAncestorRefsInFunction(Function function,
|
||||||
RecoveredClass recoveredClass) throws CancelledException {
|
RecoveredClass recoveredClass) throws CancelledException {
|
||||||
|
|
||||||
// get the map of all referenced vftables or constructor/desstructor calls in this function
|
// get the addresses in the function that refer to classes either by
|
||||||
Map<Address, RecoveredClass> referenceToClassMapForFunction =
|
// referencing a vftable in a class or by calling a function in a class
|
||||||
getReferenceToClassMap(recoveredClass, function);
|
Map<Address, ReferencedClassObject> referenceToClassMap =
|
||||||
|
functionReferenceMap.get(function);
|
||||||
|
if (referenceToClassMap == null) {
|
||||||
|
referenceToClassMap =
|
||||||
|
getReferenceToReferencedObjectsMap(recoveredClass, function);
|
||||||
|
}
|
||||||
|
|
||||||
// get a list of all ancestor classes referenced in the map
|
// get a list of all ancestor classes referenced in the map
|
||||||
List<RecoveredClass> classHierarchy = recoveredClass.getClassHierarchy();
|
List<RecoveredClass> classHierarchy = recoveredClass.getClassHierarchy();
|
||||||
|
|
||||||
// make a list of all related class references
|
// make a list of all related class references
|
||||||
List<Address> listOfAncestorRefs = new ArrayList<Address>();
|
List<Address> listOfAncestorRefs = new ArrayList<Address>();
|
||||||
Set<Address> ancestorRefs = referenceToClassMapForFunction.keySet();
|
Set<Address> ancestorRefs = referenceToClassMap.keySet();
|
||||||
for (Address ancestorRef : ancestorRefs) {
|
for (Address ancestorRef : ancestorRefs) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
RecoveredClass mappedClass = referenceToClassMapForFunction.get(ancestorRef);
|
|
||||||
|
ReferencedClassObject referencedClassObject = referenceToClassMap.get(ancestorRef);
|
||||||
|
RecoveredClass mappedClass = referencedClassObject.getContainingClass();
|
||||||
if (classHierarchy.contains(mappedClass)) {
|
if (classHierarchy.contains(mappedClass)) {
|
||||||
listOfAncestorRefs.add(ancestorRef);
|
listOfAncestorRefs.add(ancestorRef);
|
||||||
}
|
}
|
||||||
@@ -745,10 +782,11 @@ public class RecoveredClassHelper {
|
|||||||
* @return Map of Address references to Class object for the given function
|
* @return Map of Address references to Class object for the given function
|
||||||
* @throws CancelledException when cancelled
|
* @throws CancelledException when cancelled
|
||||||
*/
|
*/
|
||||||
public Map<Address, RecoveredClass> getReferenceToClassMap(RecoveredClass recoveredClass,
|
public Map<Address, ReferencedClassObject> getReferenceToReferencedObjectsMap(
|
||||||
|
RecoveredClass recoveredClass,
|
||||||
Function function) throws CancelledException {
|
Function function) throws CancelledException {
|
||||||
|
|
||||||
Map<Address, RecoveredClass> referenceToParentMap = new HashMap<Address, RecoveredClass>();
|
Map<Address, ReferencedClassObject> referenceToParentMap = new HashMap<>();
|
||||||
|
|
||||||
List<Address> vftableRefs = functionToVftableRefsMap.get(function);
|
List<Address> vftableRefs = functionToVftableRefsMap.get(function);
|
||||||
|
|
||||||
@@ -768,7 +806,9 @@ public class RecoveredClassHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RecoveredClass parentClass = vftableToClassMap.get(vftableAddress);
|
RecoveredClass parentClass = vftableToClassMap.get(vftableAddress);
|
||||||
referenceToParentMap.put(vftableRef, parentClass);
|
ReferencedClassObject referencedObject =
|
||||||
|
new ReferencedClassObject(vftableRef, vftableAddress, parentClass);
|
||||||
|
referenceToParentMap.put(vftableRef, referencedObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove duplicate vftable refs (occasionally there are LEA then MOV of same vftable address
|
// remove duplicate vftable refs (occasionally there are LEA then MOV of same vftable address
|
||||||
@@ -808,7 +848,9 @@ public class RecoveredClassHelper {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
referenceToParentMap.put(address, ancestorClass);
|
ReferencedClassObject referencedObject =
|
||||||
|
new ReferencedClassObject(address, calledFunction, ancestorClass);
|
||||||
|
referenceToParentMap.put(address, referencedObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
return referenceToParentMap;
|
return referenceToParentMap;
|
||||||
@@ -840,7 +882,7 @@ public class RecoveredClassHelper {
|
|||||||
return badFIDFunctions;
|
return badFIDFunctions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<Address, RecoveredClass> dedupeMap(Map<Address, RecoveredClass> map)
|
private Map<Address, ReferencedClassObject> dedupeMap(Map<Address, ReferencedClassObject> map)
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
|
|
||||||
// Sort the vftable refs in the order they appear in the function
|
// Sort the vftable refs in the order they appear in the function
|
||||||
@@ -852,7 +894,9 @@ public class RecoveredClassHelper {
|
|||||||
Address lastVftableRef = null;
|
Address lastVftableRef = null;
|
||||||
for (Address vftableRef : vftableRefList) {
|
for (Address vftableRef : vftableRefList) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
RecoveredClass currentClass = map.get(vftableRef);
|
|
||||||
|
ReferencedClassObject referencedObject = map.get(vftableRef);
|
||||||
|
RecoveredClass currentClass = referencedObject.getContainingClass();
|
||||||
|
|
||||||
if (lastClass != null && lastClass.equals(currentClass)) {
|
if (lastClass != null && lastClass.equals(currentClass)) {
|
||||||
// if vftable refs are within a few instructions, dedupe map
|
// if vftable refs are within a few instructions, dedupe map
|
||||||
@@ -2108,17 +2152,21 @@ public class RecoveredClassHelper {
|
|||||||
* @throws DuplicateNameException if try to create same symbol name already in namespace
|
* @throws DuplicateNameException if try to create same symbol name already in namespace
|
||||||
* @throws CircularDependencyException if parent namespace is descendant of given namespace
|
* @throws CircularDependencyException if parent namespace is descendant of given namespace
|
||||||
*/
|
*/
|
||||||
public void createListedConstructorFunctions(Map<Address, RecoveredClass> referenceToClassMap,
|
public void createListedConstructorFunctions(
|
||||||
|
Map<Address, ReferencedClassObject> referenceToClassMap,
|
||||||
List<Address> referencesToConstructors) throws CancelledException,
|
List<Address> referencesToConstructors) throws CancelledException,
|
||||||
InvalidInputException, DuplicateNameException, CircularDependencyException {
|
InvalidInputException, DuplicateNameException, CircularDependencyException {
|
||||||
|
|
||||||
for (Address constructorReference : referencesToConstructors) {
|
for (Address constructorReference : referencesToConstructors) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
|
|
||||||
RecoveredClass recoveredClass = referenceToClassMap.get(constructorReference);
|
ReferencedClassObject referencedClassObject =
|
||||||
|
referenceToClassMap.get(constructorReference);
|
||||||
|
|
||||||
|
RecoveredClass recoveredClass = referencedClassObject.getContainingClass();
|
||||||
|
|
||||||
Function constructor =
|
Function constructor =
|
||||||
extendedFlatAPI.getReferencedFunction(constructorReference, true);
|
referencedClassObject.getReferencedFunction();
|
||||||
|
|
||||||
if (constructor == null) {
|
if (constructor == null) {
|
||||||
continue;
|
continue;
|
||||||
@@ -2146,9 +2194,9 @@ public class RecoveredClassHelper {
|
|||||||
* @throws DuplicateNameException if try to create same symbol name already in namespace
|
* @throws DuplicateNameException if try to create same symbol name already in namespace
|
||||||
* @throws CircularDependencyException if parent namespace is descendant of given namespace
|
* @throws CircularDependencyException if parent namespace is descendant of given namespace
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void processInlineConstructor(RecoveredClass recoveredClass,
|
public void processInlineConstructor(RecoveredClass recoveredClass,
|
||||||
Function inlinedConstructorFunction, Map<Address, RecoveredClass> referenceToClassMap)
|
Function inlinedConstructorFunction,
|
||||||
|
Map<Address, ReferencedClassObject> referenceToClassMap)
|
||||||
throws CancelledException, InvalidInputException, DuplicateNameException,
|
throws CancelledException, InvalidInputException, DuplicateNameException,
|
||||||
CircularDependencyException {
|
CircularDependencyException {
|
||||||
|
|
||||||
@@ -2161,6 +2209,7 @@ public class RecoveredClassHelper {
|
|||||||
List<Address> referenceAddresses = new ArrayList<Address>(referenceToClassMap.keySet());
|
List<Address> referenceAddresses = new ArrayList<Address>(referenceToClassMap.keySet());
|
||||||
for (Address reference : referenceAddresses) {
|
for (Address reference : referenceAddresses) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
|
|
||||||
Address vftableAddress = getVftableAddress(reference);
|
Address vftableAddress = getVftableAddress(reference);
|
||||||
if (vftableAddress != null) {
|
if (vftableAddress != null) {
|
||||||
referencesToVftables.add(reference);
|
referencesToVftables.add(reference);
|
||||||
@@ -2178,7 +2227,10 @@ public class RecoveredClassHelper {
|
|||||||
|
|
||||||
for (Address refToVftable : referencesToVftables) {
|
for (Address refToVftable : referencesToVftables) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
RecoveredClass referencedClass = referenceToClassMap.get(refToVftable);
|
|
||||||
|
ReferencedClassObject referencedClassObject = referenceToClassMap.get(refToVftable);
|
||||||
|
|
||||||
|
RecoveredClass referencedClass = referencedClassObject.getContainingClass();
|
||||||
|
|
||||||
// last reference is the constructor
|
// last reference is the constructor
|
||||||
if (refToVftable.equals(lastRef)) {
|
if (refToVftable.equals(lastRef)) {
|
||||||
@@ -2206,7 +2258,8 @@ public class RecoveredClassHelper {
|
|||||||
* @throws DuplicateNameException if try to create same symbol name already in namespace
|
* @throws DuplicateNameException if try to create same symbol name already in namespace
|
||||||
*/
|
*/
|
||||||
public void processInlineDestructor(RecoveredClass recoveredClass,
|
public void processInlineDestructor(RecoveredClass recoveredClass,
|
||||||
Function inlinedDestructorFunction, Map<Address, RecoveredClass> referenceToClassMap)
|
Function inlinedDestructorFunction,
|
||||||
|
Map<Address, ReferencedClassObject> referenceToClassMap)
|
||||||
throws CancelledException, InvalidInputException, DuplicateNameException {
|
throws CancelledException, InvalidInputException, DuplicateNameException {
|
||||||
|
|
||||||
if (referenceToClassMap.isEmpty()) {
|
if (referenceToClassMap.isEmpty()) {
|
||||||
@@ -2236,7 +2289,9 @@ public class RecoveredClassHelper {
|
|||||||
|
|
||||||
for (Address refToVftable : referencesToVftables) {
|
for (Address refToVftable : referencesToVftables) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
RecoveredClass referencedClass = referenceToClassMap.get(refToVftable);
|
ReferencedClassObject referencedClassObject = referenceToClassMap.get(refToVftable);
|
||||||
|
|
||||||
|
RecoveredClass referencedClass = referencedClassObject.getContainingClass();
|
||||||
|
|
||||||
// last reference is the constructor
|
// last reference is the constructor
|
||||||
if (refToVftable.equals(lastRef)) {
|
if (refToVftable.equals(lastRef)) {
|
||||||
@@ -2293,7 +2348,7 @@ public class RecoveredClassHelper {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to determine if the given function calls a known constructor or inlined constructor
|
* Method to determine if the given function calls a known constructor or inlined constructor
|
||||||
* @param Set of called functions
|
* @param calledFunctions set of called functions
|
||||||
* @return true if calling function calls a known constructor or inlined constructor, false otherwise
|
* @return true if calling function calls a known constructor or inlined constructor, false otherwise
|
||||||
* @throws CancelledException if cancelled
|
* @throws CancelledException if cancelled
|
||||||
*/
|
*/
|
||||||
@@ -2313,7 +2368,7 @@ public class RecoveredClassHelper {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to determine if the given function calls a known denstructor or inlined destructor
|
* Method to determine if the given function calls a known denstructor or inlined destructor
|
||||||
* @param Set of called functions
|
* @param calledFunctions Set of called functions
|
||||||
* @return true if function calls a known constructor or inlined constructor, false otherwise
|
* @return true if function calls a known constructor or inlined constructor, false otherwise
|
||||||
* of its own or none
|
* of its own or none
|
||||||
* @throws CancelledException if cancelled
|
* @throws CancelledException if cancelled
|
||||||
@@ -2536,16 +2591,19 @@ public class RecoveredClassHelper {
|
|||||||
* @throws InvalidInputException if error setting return type
|
* @throws InvalidInputException if error setting return type
|
||||||
* @throws DuplicateNameException if try to create same symbol name already in namespace
|
* @throws DuplicateNameException if try to create same symbol name already in namespace
|
||||||
*/
|
*/
|
||||||
public void createListedDestructorFunctions(Map<Address, RecoveredClass> referenceToClassMap,
|
public void createListedDestructorFunctions(
|
||||||
|
Map<Address, ReferencedClassObject> referenceToClassMap,
|
||||||
List<Address> referencesToDestructors)
|
List<Address> referencesToDestructors)
|
||||||
throws CancelledException, InvalidInputException, DuplicateNameException {
|
throws CancelledException, InvalidInputException, DuplicateNameException {
|
||||||
|
|
||||||
for (Address destructorReference : referencesToDestructors) {
|
for (Address destructorReference : referencesToDestructors) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
|
|
||||||
RecoveredClass recoveredClass = referenceToClassMap.get(destructorReference);
|
ReferencedClassObject referencedClassObject =
|
||||||
|
referenceToClassMap.get(destructorReference);
|
||||||
|
RecoveredClass recoveredClass = referencedClassObject.getContainingClass();
|
||||||
|
|
||||||
Function destructor = extendedFlatAPI.getReferencedFunction(destructorReference, true);
|
Function destructor = referencedClassObject.getReferencedFunction();
|
||||||
if (destructor == null) {
|
if (destructor == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -4871,6 +4929,13 @@ public class RecoveredClassHelper {
|
|||||||
|
|
||||||
Symbol symbol = symbols.next();
|
Symbol symbol = symbols.next();
|
||||||
|
|
||||||
|
// function might be in multiple classes if compiler was optimized to use same function
|
||||||
|
// for multiple classes with identical functions
|
||||||
|
// let the class that has the primary symbol do the update
|
||||||
|
if (!symbol.isPrimary()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Function function = functionManager.getFunctionAt(symbol.getAddress());
|
Function function = functionManager.getFunctionAt(symbol.getAddress());
|
||||||
|
|
||||||
if (function == null) {
|
if (function == null) {
|
||||||
@@ -6145,6 +6210,8 @@ public class RecoveredClassHelper {
|
|||||||
throws CancelledException, InvalidInputException, DuplicateNameException,
|
throws CancelledException, InvalidInputException, DuplicateNameException,
|
||||||
CircularDependencyException {
|
CircularDependencyException {
|
||||||
|
|
||||||
|
Set<Function> processedFunctions = new HashSet<>();
|
||||||
|
|
||||||
for (RecoveredClass recoveredClass : recoveredClasses) {
|
for (RecoveredClass recoveredClass : recoveredClasses) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
List<Function> inlineFunctionsList =
|
List<Function> inlineFunctionsList =
|
||||||
@@ -6153,12 +6220,20 @@ public class RecoveredClassHelper {
|
|||||||
for (Function inlineFunction : inlineFunctionsList) {
|
for (Function inlineFunction : inlineFunctionsList) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
|
|
||||||
|
// functions with inlines often contain multiple inlined constructor/destructors
|
||||||
|
// skip if already processed (processInline<c/d> methods update all of them)
|
||||||
|
if (processedFunctions.contains(inlineFunction)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// get the addresses in the function that refer to classes either by
|
// get the addresses in the function that refer to classes either by
|
||||||
// referencing a vftable in a class or by calling a function in a class
|
// referencing a vftable in a class or by calling a function in a class
|
||||||
Map<Address, RecoveredClass> referenceToClassMap =
|
Map<Address, ReferencedClassObject> referenceToClassMap =
|
||||||
getReferenceToClassMap(recoveredClass, inlineFunction);
|
functionReferenceMap.get(inlineFunction);
|
||||||
List<Address> referencesToFunctions =
|
if (referenceToClassMap == null) {
|
||||||
extendedFlatAPI.getReferencesToFunctions(referenceToClassMap);
|
referenceToClassMap =
|
||||||
|
getReferenceToReferencedObjectsMap(recoveredClass, inlineFunction);
|
||||||
|
}
|
||||||
|
|
||||||
// if some of the references are to functions figure out if they are
|
// if some of the references are to functions figure out if they are
|
||||||
// constructors destructors or add them to list of indetermined
|
// constructors destructors or add them to list of indetermined
|
||||||
@@ -6166,46 +6241,48 @@ public class RecoveredClassHelper {
|
|||||||
boolean isDestructor = false;
|
boolean isDestructor = false;
|
||||||
List<Address> referenceToIndeterminates = new ArrayList<Address>();
|
List<Address> referenceToIndeterminates = new ArrayList<Address>();
|
||||||
|
|
||||||
if (!referencesToFunctions.isEmpty()) {
|
for (Address referenceAddress : referenceToClassMap.keySet()) {
|
||||||
for (Address functionReference : referencesToFunctions) {
|
|
||||||
|
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
Function function =
|
|
||||||
extendedFlatAPI.getReferencedFunction(functionReference, true);
|
|
||||||
|
|
||||||
if (function == null) {
|
ReferencedClassObject referencedClassObject =
|
||||||
continue;
|
referenceToClassMap.get(referenceAddress);
|
||||||
}
|
|
||||||
|
|
||||||
if (getAllConstructors().contains(function) ||
|
|
||||||
getAllInlinedConstructors().contains(function)) {
|
|
||||||
isConstructor = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getAllDestructors().contains(function) ||
|
|
||||||
getAllInlinedDestructors().contains(function)) {
|
|
||||||
isDestructor = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: refactor to make this function and refactor method that uses
|
|
||||||
// it to use function instead of refiguring it out
|
|
||||||
referenceToIndeterminates.add(functionReference);
|
|
||||||
|
|
||||||
|
Function function = referencedClassObject.getReferencedFunction();
|
||||||
|
if (function == null) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getAllConstructors().contains(function) ||
|
||||||
|
getAllInlinedConstructors().contains(function)) {
|
||||||
|
isConstructor = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getAllDestructors().contains(function) ||
|
||||||
|
getAllInlinedDestructors().contains(function)) {
|
||||||
|
isDestructor = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: refactor to make this function and refactor method that uses
|
||||||
|
// it to use function instead of refiguring it out
|
||||||
|
referenceToIndeterminates.add(referenceAddress);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if one or more is a constructor and none are destructors then the indeterminate
|
// if one or more is a constructor and none are destructors then the indeterminate
|
||||||
// inline is an inlined constructor
|
// inline is an inlined constructor
|
||||||
if (isConstructor == true && isDestructor == false) {
|
if (isConstructor == true && isDestructor == false) {
|
||||||
processInlineConstructor(recoveredClass, inlineFunction, referenceToClassMap);
|
processInlineConstructor(recoveredClass, inlineFunction,
|
||||||
|
referenceToClassMap);
|
||||||
|
processedFunctions.add(inlineFunction);
|
||||||
}
|
}
|
||||||
// if one or more is a destructor and none are constructors then the indeterminate
|
// if one or more is a destructor and none are constructors then the indeterminate
|
||||||
// inline is an inlined destructor
|
// inline is an inlined destructor
|
||||||
else if (isConstructor == false && isDestructor == true) {
|
else if (isConstructor == false && isDestructor == true) {
|
||||||
processInlineDestructor(recoveredClass, inlineFunction, referenceToClassMap);
|
processInlineDestructor(recoveredClass, inlineFunction, referenceToClassMap);
|
||||||
|
processedFunctions.add(inlineFunction);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
@@ -6248,6 +6325,7 @@ public class RecoveredClassHelper {
|
|||||||
processInlineConstructor(recoveredClass, inlineFunction,
|
processInlineConstructor(recoveredClass, inlineFunction,
|
||||||
referenceToClassMap);
|
referenceToClassMap);
|
||||||
isConstructor = true;
|
isConstructor = true;
|
||||||
|
processedFunctions.add(inlineFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
// inlined destructor
|
// inlined destructor
|
||||||
@@ -6255,6 +6333,7 @@ public class RecoveredClassHelper {
|
|||||||
processInlineDestructor(recoveredClass, inlineFunction,
|
processInlineDestructor(recoveredClass, inlineFunction,
|
||||||
referenceToClassMap);
|
referenceToClassMap);
|
||||||
isDestructor = true;
|
isDestructor = true;
|
||||||
|
processedFunctions.add(inlineFunction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6542,12 +6621,14 @@ public class RecoveredClassHelper {
|
|||||||
* 3. do not reference a vftable but call own destructor (call func on own c/d list) which
|
* 3. do not reference a vftable but call own destructor (call func on own c/d list) which
|
||||||
* means it is just a deleting destructor for class but has no inlined destructor
|
* means it is just a deleting destructor for class but has no inlined destructor
|
||||||
* @param recoveredClass the given class
|
* @param recoveredClass the given class
|
||||||
|
* @param vfunction the given vfunction
|
||||||
|
* @param functionsWithVftableRef all class functions with vftable references
|
||||||
* @throws CancelledException if cancelled
|
* @throws CancelledException if cancelled
|
||||||
* @throws DuplicateNameException if try to create same symbol name already in namespace
|
* @throws DuplicateNameException if try to create same symbol name already in namespace
|
||||||
* @throws InvalidInputException if issues setting return type
|
* @throws InvalidInputException if issues setting return type
|
||||||
*/
|
*/
|
||||||
private boolean processDeletingDestructor(RecoveredClass recoveredClass, Function vfunction,
|
private boolean processDeletingDestructor(RecoveredClass recoveredClass, Function vfunction,
|
||||||
List<Address> allVftables)
|
Set<Function> functionsWithVftableRef)
|
||||||
throws CancelledException, DuplicateNameException, InvalidInputException {
|
throws CancelledException, DuplicateNameException, InvalidInputException {
|
||||||
|
|
||||||
// if the virtual function IS ALSO on the class constructor/destructor list
|
// if the virtual function IS ALSO on the class constructor/destructor list
|
||||||
@@ -6555,7 +6636,7 @@ public class RecoveredClassHelper {
|
|||||||
// determine if the inline is the class or parent/grandparent class destructor
|
// determine if the inline is the class or parent/grandparent class destructor
|
||||||
boolean isDeletingDestructor = false;
|
boolean isDeletingDestructor = false;
|
||||||
|
|
||||||
if (getAllClassFunctionsWithVtableRef(allVftables).contains(vfunction)) {
|
if (functionsWithVftableRef.contains(vfunction)) {
|
||||||
|
|
||||||
recoveredClass.addDeletingDestructor(vfunction);
|
recoveredClass.addDeletingDestructor(vfunction);
|
||||||
recoveredClass.removeFromConstructorDestructorList(vfunction);
|
recoveredClass.removeFromConstructorDestructorList(vfunction);
|
||||||
@@ -6727,6 +6808,8 @@ public class RecoveredClassHelper {
|
|||||||
List<RecoveredClass> recoveredClasses) throws CancelledException, InvalidInputException,
|
List<RecoveredClass> recoveredClasses) throws CancelledException, InvalidInputException,
|
||||||
DuplicateNameException, CircularDependencyException {
|
DuplicateNameException, CircularDependencyException {
|
||||||
|
|
||||||
|
Set<Function> processedFunctions = new HashSet<>();
|
||||||
|
|
||||||
for (RecoveredClass recoveredClass : recoveredClasses) {
|
for (RecoveredClass recoveredClass : recoveredClasses) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
List<Function> indeterminateList =
|
List<Function> indeterminateList =
|
||||||
@@ -6741,16 +6824,27 @@ public class RecoveredClassHelper {
|
|||||||
|
|
||||||
for (Function indeterminateFunction : indeterminateList) {
|
for (Function indeterminateFunction : indeterminateList) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
// get the addresses in the function that refer to classes either by
|
|
||||||
// referencing a vftable in a class or by calling a function in a class
|
// functions with inlines often contain multiple inlined constructor/destructors
|
||||||
Map<Address, RecoveredClass> referenceToClassMap =
|
// skip if already processed (processInline<c/d> methods update all of them)
|
||||||
getReferenceToClassMap(recoveredClass, indeterminateFunction);
|
if (processedFunctions.contains(indeterminateFunction)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Address, ReferencedClassObject> referenceToClassMap =
|
||||||
|
functionReferenceMap.get(indeterminateFunction);
|
||||||
|
|
||||||
|
if (referenceToClassMap == null) {
|
||||||
|
referenceToClassMap =
|
||||||
|
getReferenceToReferencedObjectsMap(recoveredClass, indeterminateFunction);
|
||||||
|
}
|
||||||
|
|
||||||
List<Function> allDescendantConstructors =
|
List<Function> allDescendantConstructors =
|
||||||
getAllDescendantConstructors(recoveredClass);
|
getAllDescendantConstructors(recoveredClass);
|
||||||
if (allDescendantConstructors.contains(indeterminateFunction)) {
|
if (allDescendantConstructors.contains(indeterminateFunction)) {
|
||||||
processInlineConstructor(recoveredClass, indeterminateFunction,
|
processInlineConstructor(recoveredClass, indeterminateFunction,
|
||||||
referenceToClassMap);
|
referenceToClassMap);
|
||||||
|
processedFunctions.add(indeterminateFunction);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6759,6 +6853,7 @@ public class RecoveredClassHelper {
|
|||||||
if (allDescendantDestructors.contains(indeterminateFunction)) {
|
if (allDescendantDestructors.contains(indeterminateFunction)) {
|
||||||
processInlineDestructor(recoveredClass, indeterminateFunction,
|
processInlineDestructor(recoveredClass, indeterminateFunction,
|
||||||
referenceToClassMap);
|
referenceToClassMap);
|
||||||
|
processedFunctions.add(indeterminateFunction);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6787,12 +6882,14 @@ public class RecoveredClassHelper {
|
|||||||
if (ancestorConstructor != null) {
|
if (ancestorConstructor != null) {
|
||||||
processInlineConstructor(recoveredClass, indeterminateFunction,
|
processInlineConstructor(recoveredClass, indeterminateFunction,
|
||||||
referenceToClassMap);
|
referenceToClassMap);
|
||||||
|
processedFunctions.add(indeterminateFunction);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ancestorDestructor != null) {
|
if (ancestorDestructor != null) {
|
||||||
processInlineDestructor(recoveredClass, indeterminateFunction,
|
processInlineDestructor(recoveredClass, indeterminateFunction,
|
||||||
referenceToClassMap);
|
referenceToClassMap);
|
||||||
|
processedFunctions.add(indeterminateFunction);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6919,7 +7016,8 @@ public class RecoveredClassHelper {
|
|||||||
|
|
||||||
// process deleting destructors if type 1, 2 or 3
|
// process deleting destructors if type 1, 2 or 3
|
||||||
boolean isDeletingDestructor =
|
boolean isDeletingDestructor =
|
||||||
processDeletingDestructor(recoveredClass, vfunction, allVftables);
|
processDeletingDestructor(recoveredClass, vfunction,
|
||||||
|
allFunctionsThatRefVftables);
|
||||||
if (isDeletingDestructor) {
|
if (isDeletingDestructor) {
|
||||||
processPossibleDestructors(allPossibleCDs, possibleCalledDestructors, vfunction,
|
processPossibleDestructors(allPossibleCDs, possibleCalledDestructors, vfunction,
|
||||||
allVftables);
|
allVftables);
|
||||||
@@ -8748,4 +8846,103 @@ public class RecoveredClassHelper {
|
|||||||
return classStructureDataType;
|
return classStructureDataType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ReferencedClassObject {
|
||||||
|
|
||||||
|
Address referenceLocation;
|
||||||
|
RecoveredClass containingClass;
|
||||||
|
Object referencedObject;
|
||||||
|
Function referencedFunction;
|
||||||
|
Address referencedAddress;
|
||||||
|
Boolean isConstructor;
|
||||||
|
Boolean isDestructor;
|
||||||
|
|
||||||
|
public ReferencedClassObject(Address referenceLocation, Object referencedObject,
|
||||||
|
RecoveredClass containingClass) {
|
||||||
|
this.referenceLocation = referenceLocation;
|
||||||
|
this.referencedObject = referencedObject;
|
||||||
|
this.containingClass = containingClass;
|
||||||
|
|
||||||
|
if (referencedObject instanceof Function function) {
|
||||||
|
referencedFunction = function;
|
||||||
|
referencedAddress = function.getEntryPoint();
|
||||||
|
}
|
||||||
|
else if (referencedObject instanceof Address address) {
|
||||||
|
referencedAddress = address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to return the address of the reference location
|
||||||
|
* @return the address of the reference location
|
||||||
|
*/
|
||||||
|
public Address getReferenceLocation() {
|
||||||
|
return referenceLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to return the referenced address
|
||||||
|
* @return the referenced address or null if the referenced object is not an address
|
||||||
|
*/
|
||||||
|
public Address getReferencedAddress() {
|
||||||
|
return referencedAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to return the referenced function
|
||||||
|
* @return the referenced function or null if the referenced object is not a function
|
||||||
|
*/
|
||||||
|
public Function getReferencedFunction() {
|
||||||
|
return referencedFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to return the RecoveredClass that corresponds to the namespace that contains the
|
||||||
|
* given referenced object
|
||||||
|
* @return the RecoveredClass object for the namespace that contains the referenced object
|
||||||
|
*/
|
||||||
|
public RecoveredClass getContainingClass() {
|
||||||
|
return containingClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to set whether the referenced object is a constructor or not
|
||||||
|
* @param choice should be set to true if it is a constructor and false if not
|
||||||
|
*/
|
||||||
|
public void setIsConstructor(Boolean choice) {
|
||||||
|
isConstructor = choice;
|
||||||
|
// Note that the opposite is not necessarily true
|
||||||
|
if (isConstructor) {
|
||||||
|
isDestructor = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to return whether the referenced object is a constructor
|
||||||
|
* @return true if a constructor, false if not a constructor, null if unknown
|
||||||
|
*/
|
||||||
|
public Boolean isConstructor() {
|
||||||
|
return isConstructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to set whether the referenced object is a destructor or not
|
||||||
|
* @param choice should be set to true if it is a destructor and false if not
|
||||||
|
*/
|
||||||
|
public void setIsDestructor(Boolean choice) {
|
||||||
|
isDestructor = choice;
|
||||||
|
// Note that the opposite is not necessarily true
|
||||||
|
if (isDestructor) {
|
||||||
|
isConstructor = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to return whether the referenced object is a destructor
|
||||||
|
* @return true if a destructor, false if not a destructor, null if unknown
|
||||||
|
*/
|
||||||
|
public Boolean isDestructor() {
|
||||||
|
return isDestructor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user