diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/DecompilerScriptUtils.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/DecompilerScriptUtils.java index 2cc9ca3d51..ebc15b5ed8 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/DecompilerScriptUtils.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/DecompilerScriptUtils.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. @@ -16,10 +16,8 @@ //DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS. package classrecovery; -import docking.options.OptionsService; import ghidra.app.decompiler.*; import ghidra.app.decompiler.component.DecompilerUtils; -import ghidra.framework.options.ToolOptions; import ghidra.framework.plugintool.ServiceProvider; import ghidra.program.model.address.Address; import ghidra.program.model.data.DataType; @@ -27,7 +25,10 @@ import ghidra.program.model.data.ParameterDefinition; import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Program; import ghidra.program.model.pcode.*; -import ghidra.util.exception.CancelledException; +import ghidra.program.model.pcode.HighFunctionDBUtil.ReturnCommitOption; +import ghidra.program.model.symbol.SourceType; +import ghidra.util.Msg; +import ghidra.util.exception.*; import ghidra.util.task.TaskMonitor; public class DecompilerScriptUtils { @@ -109,6 +110,30 @@ public class DecompilerScriptUtils { return decompRes.getHighFunction().getFunctionPrototype().getReturnType(); } + public void commitFunction(Function function) { + DecompileResults decompRes = decompInterface.decompileFunction(function, + decompInterface.getOptions().getDefaultTimeout(), monitor); + + if (decompRes == null || decompRes.getHighFunction() == null || + decompRes.getHighFunction().getFunctionPrototype() == null) { + Msg.debug(this, "Couldn't commit params - null high function"); + return; + } + + try { + HighFunctionDBUtil.commitParamsToDatabase(decompRes.getHighFunction(), true, + ReturnCommitOption.COMMIT, SourceType.ANALYSIS); + } + catch (DuplicateNameException e) { + Msg.debug(this, "Couldn't commit params " + e); + return; + } + catch (InvalidInputException e) { + Msg.debug(this, "Couldn't commit params " + e); + return; + } + } + /** * Method to retrieve the function signature string from the decompiler function prototype. NOTE: * if there is a this param, it will not be included. diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java index e62e551dae..7c798d5694 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java @@ -479,7 +479,8 @@ public class RecoveredClassHelper { return functionToLoadPcodeOps.get(function); } - public Set getAllVfunctions(List
vftableAddresses) throws CancelledException { + public Set getAllVfunctions(List
vftableAddresses) + throws CancelledException { if (vftableAddresses.isEmpty()) { return Collections.emptySet(); } @@ -3294,6 +3295,14 @@ public class RecoveredClassHelper { public void addConstructorsToClassNamespace(RecoveredClass recoveredClass, Structure classStruct) throws Exception { + DataType undefinedDT = null; + if (defaultPointerSize == 4) { + undefinedDT = new Undefined4DataType(); + } + if (defaultPointerSize == 8) { + undefinedDT = new Undefined8DataType(); + } + Namespace classNamespace = recoveredClass.getClassNamespace(); String className = recoveredClass.getName(); @@ -3310,70 +3319,53 @@ public class RecoveredClassHelper { true); } - // if current decompiler function return type is a pointer then set the return type - // to a pointer to the class structure, otherwise if it is a void, make it a void so the - // listing has void too, otherwise, leave it as is, probably a void - String returnType = getReturnTypeFromDecompiler(constructorFunction); + // commit what the decompiler knows first so that retyping will not + // completely overwrite decompiler with listing signature + decompilerUtils.commitFunction(constructorFunction); - // Set error bookmark, add error message, and get the listing return type if the - // decompiler return type is null - if (returnType == null) { + HighFunction highFunction = decompilerUtils.getHighFunction(constructorFunction); + if (highFunction == null) { + String msg = + "Decompiler Error: Failed to decompile function possibly due to the addition of class structure. "; - String msg1 = "Decompiler Error: Failed to decompile function"; - String msg2 = ", possibly due to the addition of class structure."; - - Msg.debug(this, msg1 + " at " + constructorFunction.getEntryPoint() + msg2); + Msg.debug(this, msg + constructorFunction.getEntryPoint()); program.getBookmarkManager() .setBookmark(constructorFunction.getEntryPoint(), BookmarkType.ERROR, - "Decompiler Error", msg1 + msg2); - - // get the return type from the listing and in some cases it will - // indicate the correct type to help determine the below type to add - returnType = constructorFunction.getReturnType().getDisplayName(); + "Decompiler Error", msg); + continue; } - if (returnType.equals("void")) { - constructorFunction.setReturnType(VoidDataType.dataType, SourceType.ANALYSIS); + DataType returnType = highFunction.getFunctionPrototype().getReturnType(); + if (returnType == null) { + Msg.debug(this, + "ERROR: Return type is null " + constructorFunction.getEntryPoint()); + continue; } - else if (returnType.contains("*")) { - DataType classPointerDataType = dataTypeManager.getPointer(classStruct); - constructorFunction.setReturnType(classPointerDataType, SourceType.ANALYSIS); - } - // if neither and it is a FID function change it to undefined so the decompiler will + + // if a FID function and isn't void or * change it to undefined so the decompiler will // recompute it - else if (isFidFunction(constructorFunction)) { - DataType undefinedDT = null; - if (defaultPointerSize == 4) { - undefinedDT = new Undefined4DataType(); - } - if (defaultPointerSize == 8) { - undefinedDT = new Undefined8DataType(); - } + String returnTypeString = returnType.getDisplayName(); + if (isFidFunction(constructorFunction) && returnTypeString != "void" && + !returnTypeString.contains("*")) { + if (undefinedDT != null) { constructorFunction.setReturnType(undefinedDT, SourceType.ANALYSIS); } } + // if return type is a pointer then make sure it is the class structure + if (returnType.getDisplayName().contains("*")) { + DataType classPointerDataType = dataTypeManager.getPointer(classStruct); + if (!returnType.isEquivalent(classPointerDataType)) { + constructorFunction.setReturnType(classPointerDataType, + SourceType.ANALYSIS); + } + } + } } - /** - * Get the return value from the decompiler signature for the given function - * @param function the given function - * @return the decompiler return value for the given function - */ - private String getReturnTypeFromDecompiler(Function function) { - - DataType decompilerReturnType = decompilerUtils.getDecompilerReturnType(function); - - if (decompilerReturnType == null) { - return null; - } - - return decompilerReturnType.getDisplayName(); - } - /** * Method to name class destructors and add them to class namespace * @param recoveredClass current class @@ -3399,8 +3391,7 @@ public class RecoveredClassHelper { createNewSymbolAtFunction(destructorFunction, destructorName, classNamespace, true, true); } - - destructorFunction.setReturnType(VoidDataType.dataType, SourceType.ANALYSIS); + decompilerUtils.commitFunction(destructorFunction); } } @@ -3426,6 +3417,7 @@ public class RecoveredClassHelper { createNewSymbolAtFunction(destructorFunction, destructorName, classNamespace, false, false); + decompilerUtils.commitFunction(destructorFunction); } } @@ -3450,8 +3442,7 @@ public class RecoveredClassHelper { createNewSymbolAtFunction(vbaseDestructorFunction, destructorName, classNamespace, true, true); } - - vbaseDestructorFunction.setReturnType(VoidDataType.dataType, SourceType.ANALYSIS); + decompilerUtils.commitFunction(vbaseDestructorFunction); } } @@ -3606,6 +3597,7 @@ public class RecoveredClassHelper { function.getEntryPoint().toString()); } return; + } symbol = lcmd.getSymbol(); @@ -4674,6 +4666,7 @@ public class RecoveredClassHelper { createNewSymbolAtFunction(vfunction, vfunctionName, classNamespace, setPrimary, removeBadFID); } + decompilerUtils.commitFunction(vfunction); } } } @@ -5040,6 +5033,10 @@ public class RecoveredClassHelper { if (nameVfunctions) { createNewSymbolAtFunction(indeterminateFunction, className + "_Constructor_or_Destructor", classNamespace, false, false); + // in this case since indeterminate, only commit if script names it + // if name flag is not set then it will have correct name from debug and be handled + // in other methods (ie addConst, addDest) + decompilerUtils.commitFunction(indeterminateFunction); } }