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.

This commit is contained in:
ghidra007 2024-08-30 14:47:36 +00:00
parent d87add933e
commit 7825f8fd4d
2 changed files with 79 additions and 57 deletions

View File

@ -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.

View File

@ -479,7 +479,8 @@ public class RecoveredClassHelper {
return functionToLoadPcodeOps.get(function);
}
public Set<Function> getAllVfunctions(List<Address> vftableAddresses) throws CancelledException {
public Set<Function> getAllVfunctions(List<Address> 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);
}
}