diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java index 8417cece2d..f36c713735 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -426,21 +426,23 @@ public class RecoveredClassHelper { // of number of CALL instructions even if the call reg type functionCallMap.put(instruction.getMinAddress(), calledFunction); } - if(instruction.getFlowOverride().equals(FlowOverride.CALL_RETURN)) { + if (instruction.getFlowOverride().equals(FlowOverride.CALL_RETURN)) { Reference reference = instruction.getPrimaryReference(0); if (reference == null) { continue; } Address functionAddress = reference.getFromAddress(); - Function secondHalfOfFunction = extendedFlatAPI.getReferencedFunction(functionAddress); - if(secondHalfOfFunction != null){ - Map functionCallMap2 = getFunctionCallMap(secondHalfOfFunction,false); - for(Address addr : functionCallMap2.keySet()) { + Function secondHalfOfFunction = + extendedFlatAPI.getReferencedFunction(functionAddress); + if (secondHalfOfFunction != null) { + Map functionCallMap2 = + getFunctionCallMap(secondHalfOfFunction, false); + for (Address addr : functionCallMap2.keySet()) { monitor.checkCancelled(); functionCallMap.put(addr, functionCallMap2.get(addr)); } } - + } } return functionCallMap; @@ -2264,15 +2266,14 @@ public class RecoveredClassHelper { for (Function calledFunction : calledFunctions) { monitor.checkCancelled(); - if (getAllConstructors().contains(calledFunction) || getAllInlinedConstructors().contains(calledFunction)) { + if (getAllConstructors().contains(calledFunction) || + getAllInlinedConstructors().contains(calledFunction)) { return true; } } return false; } - - /** * Method to determine if the given function calls a known denstructor or inlined destructor @@ -2286,32 +2287,32 @@ public class RecoveredClassHelper { for (Function calledFunction : calledFunctions) { monitor.checkCancelled(); - if (getAllDestructors().contains(calledFunction) || getAllInlinedDestructors().contains(calledFunction)) { + if (getAllDestructors().contains(calledFunction) || + getAllInlinedDestructors().contains(calledFunction)) { return true; } } return false; } - - private boolean callsOwnFunction(RecoveredClass recoveredClass, Set calledFunctions) throws CancelledException { - + + private boolean callsOwnFunction(RecoveredClass recoveredClass, Set calledFunctions) + throws CancelledException { + for (Function calledFunction : calledFunctions) { monitor.checkCancelled(); - - if(recoveredClass.getConstructorOrDestructorFunctions().contains(calledFunction)) { + + if (recoveredClass.getConstructorOrDestructorFunctions().contains(calledFunction)) { return true; } } return false; } - - + private Set getCalledFunctions(Function callingFunction) throws CancelledException { - Set calledFunctions = new HashSet(); - + InstructionIterator instructions = callingFunction.getProgram() .getListing() .getInstructions(callingFunction.getBody(), true); @@ -2325,11 +2326,11 @@ public class RecoveredClassHelper { if (calledFunction == null) { continue; } - + calledFunctions.add(calledFunction); } } - + return calledFunctions; } @@ -2571,7 +2572,8 @@ public class RecoveredClassHelper { * @param recoveredClass the given class object * @return true if class has a vbase destructor, false if not */ - private boolean hasValidVbaseDestructor(RecoveredClass recoveredClass) throws CancelledException { + private boolean hasValidVbaseDestructor(RecoveredClass recoveredClass) + throws CancelledException { Function vBaseDestructor = recoveredClass.getVBaseDestructor(); StringBuffer string = new StringBuffer(); @@ -4453,7 +4455,7 @@ public class RecoveredClassHelper { String nameField = vfunction.getName(); FunctionDefinition functionDataType = - new FunctionDefinitionDataType(vfunction, true); + new FunctionDefinitionDataType(vfunction, false); if (!vfunction.getName().equals(functionDefName)) { functionDataType.setName(functionDefName); @@ -4467,24 +4469,38 @@ public class RecoveredClassHelper { nameField = DEFAULT_VFUNCTION_PREFIX + vfunctionNumber; - // get function sig from child class + // get function sig from a child class Function childVirtualFunction = - getChildVirtualFunction(recoveredClass, vftableAddress, vfunctionNumber); + getChildVirtualFunction(recoveredClass, vfunctionNumber); + + // if it is null it will just use the purecall function definition since + // it can't find a child one to use to replace it if (childVirtualFunction != null) { functionDataType = - new FunctionDefinitionDataType(childVirtualFunction, true); + new FunctionDefinitionDataType(childVirtualFunction, false); functionDataType.setReturnType(childVirtualFunction.getReturnType()); Symbol childFunctionSymbol = symbolTable.getPrimarySymbol(childVirtualFunction.getEntryPoint()); // if the child function has a default name, rename the function definition // data type to the "vfunction" name - if (childFunctionSymbol.getSource() == SourceType.DEFAULT) { - functionDataType.setName(nameField); + if (childFunctionSymbol.getSource() != SourceType.DEFAULT) { + nameField = childFunctionSymbol.getName(); } } + functionDataType.setName(nameField); comment = recoveredClass.getName() + " pure " + comment; + } + ParameterDefinition[] arguments = functionDataType.getArguments(); + + // if the vfunction is a thiscall then replace the classStruct* this with voidPtr + // so that it can be used generically for all related members of the class family + if (arguments.length > 0 && arguments[0].getName().equals("this")) { + VoidDataType voidDT = new VoidDataType(); + PointerDataType voidPtr = new PointerDataType(voidDT); + ParameterDefinition parameterDefinition = arguments[0]; + parameterDefinition.setDataType(voidPtr); } PointerDataType functionPointerDataType = @@ -4515,9 +4531,12 @@ public class RecoveredClassHelper { * @param recoveredClass the given class * @param virtualFunctionNumber the virtual function offset into the table * @return a child class virtual function at the given offset + * @throws CancelledException if cancelled */ - private Function getChildVirtualFunction(RecoveredClass recoveredClass, Address vftableAddress, - int virtualFunctionNumber) { + private Function getChildVirtualFunction(RecoveredClass recoveredClass, + int virtualFunctionNumber) throws CancelledException { + + Function nonThisFunction = null; List childClasses = recoveredClass.getChildClasses(); if (childClasses.isEmpty()) { @@ -4526,29 +4545,42 @@ public class RecoveredClassHelper { // The child functions should all have the same function signature so just get any one of them // if for some reason they don't, still have to pick one and let user decide how to update - RecoveredClass childClass = childClasses.get(0); + for (RecoveredClass childClass : childClasses) { + monitor.checkCancelled(); - List
childVftableAddresses = childClass.getVftableAddresses(); - if (childVftableAddresses.isEmpty()) { - return null; - } - - // get the correct child vftable for the given parent class - for (Address childVftableAddress : childVftableAddresses) { - RecoveredClass parentForVftable = childClass.getVftableBaseClass(childVftableAddress); - if (parentForVftable == null) { + List
childVftableAddresses = childClass.getVftableAddresses(); + if (childVftableAddresses.isEmpty()) { continue; } - if (parentForVftable.equals(recoveredClass)) { - List childVirtualFunctionsForGivenParent = - childClass.getVirtualFunctions(childVftableAddress); - if (childVirtualFunctionsForGivenParent.size() < virtualFunctionNumber) { - return null; + + // get the correct child vftable for the given parent class + for (Address childVftableAddress : childVftableAddresses) { + RecoveredClass parentForVftable = + childClass.getVftableBaseClass(childVftableAddress); + if (parentForVftable == null) { + continue; + } + if (parentForVftable.equals(recoveredClass)) { + List childVirtualFunctionsForGivenParent = + childClass.getVirtualFunctions(childVftableAddress); + if (childVirtualFunctionsForGivenParent.size() < virtualFunctionNumber) { + continue; + } + Function vfunction = + childVirtualFunctionsForGivenParent.get(virtualFunctionNumber - 1); + Parameter[] parameters = vfunction.getParameters(); + if (parameters.length == 0) { + continue; + } + if (parameters[0].getName().equals("this")) { + return vfunction; + } + + nonThisFunction = vfunction; } - return childVirtualFunctionsForGivenParent.get(virtualFunctionNumber - 1); } } - return null; + return nonThisFunction; //or null if no vfunctions at all which should never happen } /** @@ -5420,12 +5452,12 @@ public class RecoveredClassHelper { // if inline, put on separate list and remove from indeterminate list // process later - if(callsOwnConstructorOrDestructor(recoveredClass, indeterminateFunction)) { + if (callsOwnConstructorOrDestructor(recoveredClass, indeterminateFunction)) { recoveredClass.addIndeterminateInline(indeterminateFunction); indeterminateIterator.remove(); continue; } - + if (vftableReferenceList.size() > 1) { if (!areVftablesInSameClass(vftableReferenceList)) { recoveredClass.addIndeterminateInline(indeterminateFunction); @@ -5435,16 +5467,18 @@ public class RecoveredClassHelper { } } } - - private boolean callsOwnConstructorOrDestructor(RecoveredClass recoveredClass, Function function) throws CancelledException { - + + private boolean callsOwnConstructorOrDestructor(RecoveredClass recoveredClass, + Function function) throws CancelledException { + Set calledFunctions = getCalledFunctions(function); - - List constructorOrDestructorFunctions = recoveredClass.getConstructorOrDestructorFunctions(); - for(Function cdFunction : constructorOrDestructorFunctions) { + + List constructorOrDestructorFunctions = + recoveredClass.getConstructorOrDestructorFunctions(); + for (Function cdFunction : constructorOrDestructorFunctions) { monitor.checkCancelled(); - - if(calledFunctions.contains(cdFunction)) { + + if (calledFunctions.contains(cdFunction)) { return true; } } @@ -6133,10 +6167,10 @@ public class RecoveredClassHelper { // weed out any that call own possible constructors and destructors // as they will not be const/dest (possibly may be inlined one though Set calledFunctions = getCalledFunctions(indeterminateFunction); - if(callsOwnFunction(recoveredClass, calledFunctions)) { + if (callsOwnFunction(recoveredClass, calledFunctions)) { continue; } - + // first try identifying using known constructors and destructors boolean callsKnownConstructor = callsKnownConstructor(calledFunctions); boolean callsKnownDestructor = callsKnownDestructor(calledFunctions); @@ -6164,7 +6198,7 @@ public class RecoveredClassHelper { // Next try identifying constructors using decompiler return type DataType decompilerReturnType = decompilerUtils.getDecompilerReturnType(indeterminateFunction); - + if (decompilerReturnType != null) { String returnDataName = decompilerReturnType.getDisplayName(); @@ -7622,7 +7656,7 @@ public class RecoveredClassHelper { return null; } - FunctionSignature listingFunctionSignature = vfunction.getSignature(true); + FunctionSignature listingFunctionSignature = vfunction.getSignature(false); FunctionDefinition componentFunctionDefinition = getComponentFunctionDefinition(structureComponent); @@ -8195,7 +8229,7 @@ public class RecoveredClassHelper { vfunction = vfunction.getThunkedFunction(true); } - FunctionSignature listingFunctionSignature = vfunction.getSignature(true); + FunctionSignature listingFunctionSignature = vfunction.getSignature(false); if (listingFunctionSignature.getName().contains("purecall")) { return null;