From 7825f8fd4d96b4812833d5c9111ae9fbfcfb52cd Mon Sep 17 00:00:00 2001 From: ghidra007 Date: Fri, 30 Aug 2024 14:47:36 +0000 Subject: [PATCH] GP-4872 update to all add function to namespaces methods to commit the function so as to not overwrite decomipler when making other changes via listing. Also added check for existing equivalent listing constructor return type before setting it to class structure pointer. --- .../classrecovery/DecompilerScriptUtils.java | 35 +++++- .../classrecovery/RecoveredClassHelper.java | 101 +++++++++--------- 2 files changed, 79 insertions(+), 57 deletions(-) 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); } }