diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/ApplyFunctionSignatureCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/ApplyFunctionSignatureCmd.java index c254246d6d..6150b8db97 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/ApplyFunctionSignatureCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/ApplyFunctionSignatureCmd.java @@ -213,14 +213,14 @@ public class ApplyFunctionSignatureCmd extends BackgroundCommand { returnDt = prepareDataType(returnDt, targetDtm, dtCleaner); } - List params = createParameters(compilerSpec, conventionName, args); + ReturnParameterImpl returnParam = new ReturnParameterImpl(returnDt, program); + List params = + createParameters(compilerSpec, conventionName, args, returnParam); SymbolTable symbolTable = program.getSymbolTable(); adjustParameterNamesToAvoidConflicts(symbolTable, func, params); - ReturnParameterImpl returnParam = new ReturnParameterImpl(returnDt, program); - func.updateFunction(conventionName, returnParam, params, FunctionUpdateType.DYNAMIC_STORAGE_FORMAL_PARAMS, false, source); func.setVarArgs(signature.hasVarArgs()); @@ -247,7 +247,9 @@ public class ApplyFunctionSignatureCmd extends BackgroundCommand { } private List createParameters(CompilerSpec compilerSpec, String conventionName, - ParameterDefinition[] args) throws InvalidInputException { + ParameterDefinition[] args, Parameter returnParam) throws InvalidInputException { + + DataType returnDt = returnParam.getDataType(); int firstParamIndex = getIndexOfFirstParameter(conventionName, args); @@ -256,11 +258,15 @@ public class ApplyFunctionSignatureCmd extends BackgroundCommand { DataTypeManager dtm = program.getDataTypeManager(); for (int i = firstParamIndex; i < args.length; i++) { String name = args[i].getName(); + DataType type = args[i].getDataType().clone(dtm); if (Function.RETURN_PTR_PARAM_NAME.equals(name)) { - continue; // discard what should be an auto-param + if ((type instanceof Pointer) && + (type.isEquivalent(returnDt) || VoidDataType.dataType.isEquivalent(returnDt))) { + returnParam.setDataType(((Pointer) type).getDataType(), source); + } + continue; // remove what should be an auto-param } - DataType type = args[i].getDataType().clone(dtm); if (settleCTypes) { type = settleCDataType(type, dtm); } @@ -269,6 +275,7 @@ public class ApplyFunctionSignatureCmd extends BackgroundCommand { param.setComment(args[i].getComment()); params.add(param); } + return params; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/ParameterDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/ParameterDB.java index 0124d38743..a5cad40ed9 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/ParameterDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/ParameterDB.java @@ -54,10 +54,10 @@ class ParameterDB extends VariableDB implements Parameter { @Override public DataType getDataType() { DataType dt = getFormalDataType(); - VariableStorage varStorage = getVariableStorage(); - if (varStorage.isForcedIndirect()) { + if (isForcedIndirect()) { Program program = function.getProgram(); DataTypeManager dtm = program.getDataTypeManager(); + VariableStorage varStorage = getVariableStorage(); int ptrSize = varStorage.size(); if (ptrSize != dtm.getDataOrganization().getPointerSize()) { dt = dtm.getPointer(dt, ptrSize); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/ReturnParameterDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/ReturnParameterDB.java index 76d6b21d03..4f97595949 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/ReturnParameterDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/ReturnParameterDB.java @@ -18,6 +18,7 @@ package ghidra.program.database.function; import java.io.IOException; import ghidra.program.model.data.*; +import ghidra.program.model.lang.DynamicVariableStorage; import ghidra.program.model.listing.*; import ghidra.program.model.symbol.SourceType; import ghidra.program.util.ChangeManager; @@ -45,8 +46,8 @@ public class ReturnParameterDB extends ParameterDB { } @Override - public void setName(String name, SourceType source) throws DuplicateNameException, - InvalidInputException { + public void setName(String name, SourceType source) + throws DuplicateNameException, InvalidInputException { throw new UnsupportedOperationException(); } @@ -81,10 +82,9 @@ public class ReturnParameterDB extends ParameterDB { newStorage = VariableStorage.UNASSIGNED_STORAGE; } Program program = function.getProgram(); - type = - VariableUtilities.checkDataType(type, - newStorage.isVoidStorage() || newStorage.isUnassignedStorage(), getLength(), - program); + type = VariableUtilities.checkDataType(type, + newStorage.isVoidStorage() || newStorage.isUnassignedStorage(), getLength(), + program); if (!newStorage.isUnassignedStorage()) { newStorage = VariableUtilities.checkStorage(function, newStorage, type, force); } @@ -163,6 +163,19 @@ public class ReturnParameterDB extends ParameterDB { return dataType; } + @Override + public DataType getDataType() { + if (storage == DynamicVariableStorage.INDIRECT_VOID_STORAGE) { + return VoidDataType.dataType; + } + return super.getDataType(); + } + + @Override + public boolean isForcedIndirect() { + return storage.isForcedIndirect(); + } + @Override public SourceType getSource() { if (dataType == null || Undefined.isUndefined(dataType)) { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/DynamicVariableStorage.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/DynamicVariableStorage.java index 2496c4b6c6..0136fb4fc9 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/DynamicVariableStorage.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/DynamicVariableStorage.java @@ -22,11 +22,28 @@ import ghidra.program.model.pcode.Varnode; import ghidra.util.exception.InvalidInputException; public class DynamicVariableStorage extends VariableStorage { - + + /** + * INDIRECT_VOID_STORAGE used to identify return storage which is "mapped" + * with a data-type of void but was forced indirect with the corresponding use of a + * hidden return-storage-parameter. + */ + public static final DynamicVariableStorage INDIRECT_VOID_STORAGE = new DynamicVariableStorage(); + private AutoParameterType autoParamType; private boolean forcedIndirect; private boolean isUnassigned = false; - + private boolean isVoid = false; + + /** + * Construct void return storage with forced-indirect flag. + */ + private DynamicVariableStorage() { + super(); + forcedIndirect = true; + isVoid = true; + } + /** * Construct Unassigned dynamic variable storage with an optional auto-parameter type * @param autoParamType auto-parameter type or null if not applicable @@ -36,7 +53,7 @@ public class DynamicVariableStorage extends VariableStorage { this.autoParamType = autoParamType; isUnassigned = true; } - + /** * Construct dynamic variable storage * @param program @@ -48,7 +65,7 @@ public class DynamicVariableStorage extends VariableStorage { this.forcedIndirect = forcedIndirect; isUnassigned = true; } - + /** * Construct dynamic variable storage with an optional auto-parameter type * @param program @@ -58,8 +75,7 @@ public class DynamicVariableStorage extends VariableStorage { * @throws InvalidInputException */ public DynamicVariableStorage(ProgramArchitecture program, AutoParameterType autoParamType, - Address address, - int size) throws InvalidInputException { + Address address, int size) throws InvalidInputException { super(program, address, size); this.autoParamType = autoParamType; } @@ -72,8 +88,7 @@ public class DynamicVariableStorage extends VariableStorage { * @throws InvalidInputException if specified varnodes violate storage restrictions */ public DynamicVariableStorage(ProgramArchitecture program, AutoParameterType autoParamType, - Varnode... varnodes) - throws InvalidInputException { + Varnode... varnodes) throws InvalidInputException { super(program, varnodes); this.autoParamType = autoParamType; } @@ -88,8 +103,7 @@ public class DynamicVariableStorage extends VariableStorage { * @throws InvalidInputException */ public DynamicVariableStorage(ProgramArchitecture program, boolean forcedIndirect, - Address address, int size) - throws InvalidInputException { + Address address, int size) throws InvalidInputException { super(program, address, size); this.forcedIndirect = forcedIndirect; } @@ -103,8 +117,7 @@ public class DynamicVariableStorage extends VariableStorage { * @throws InvalidInputException if specified varnodes violate storage restrictions */ public DynamicVariableStorage(ProgramArchitecture program, boolean forcedIndirect, - Varnode... varnodes) - throws InvalidInputException { + Varnode... varnodes) throws InvalidInputException { super(program, varnodes); this.forcedIndirect = forcedIndirect; } @@ -124,6 +137,11 @@ public class DynamicVariableStorage extends VariableStorage { return isUnassigned; } + @Override + public boolean isVoidStorage() { + return isVoid; + } + @Override public AutoParameterType getAutoParameterType() { return autoParamType; @@ -132,7 +150,7 @@ public class DynamicVariableStorage extends VariableStorage { @Override public String toString() { String str = super.toString(); - if (forcedIndirect) { + if (forcedIndirect && varnodes != null) { str = str + " (ptr)"; } if (autoParamType != null) { @@ -140,23 +158,26 @@ public class DynamicVariableStorage extends VariableStorage { } return str; } - + /** * Construct Unassigned dynamic variable storage with an optional auto-parameter type. * NOTE: The {@link #isUnassignedStorage()} method should be used to * detect this type of storage. * @param autoParamType auto-parameter type or null if not applicable + * @return Unassigned dynamic variable storage */ - public static DynamicVariableStorage getUnassignedDynamicStorage(AutoParameterType autoParamType) { + public static DynamicVariableStorage getUnassignedDynamicStorage( + AutoParameterType autoParamType) { return new DynamicVariableStorage(autoParamType); } - + /** * Construct Unassigned dynamic variable storage. * NOTE: The {@link #isUnassignedStorage()} method should be used to * detect this type of storage. * @param forcedIndirect if true indicates that the parameter has been forced to pass * as a pointer instead of its raw type + * @return Unassigned dynamic variable storage */ public static DynamicVariableStorage getUnassignedDynamicStorage(boolean forcedIndirect) { return new DynamicVariableStorage(forcedIndirect); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamListStandardOut.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamListStandardOut.java index 7fd5eb4f3c..1d2817445e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamListStandardOut.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamListStandardOut.java @@ -60,8 +60,8 @@ public class ParamListStandardOut extends ParamListStandard { else { assignAddressFallback(StorageClass.PTR, pointerType, false, status, store); store.type = pointerType; - store.isIndirect = true; // Signal that there is a hidden return } + store.isIndirect = true; // Signal that there is a hidden return if (addAutoParams) { ParameterPieces hiddenRet = new ParameterPieces(); hiddenRet.type = pointerType; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParameterPieces.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParameterPieces.java index db9ea882ca..40b314a2fe 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParameterPieces.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParameterPieces.java @@ -66,6 +66,9 @@ public class ParameterPieces { type = DataType.DEFAULT; } if (VoidDataType.isVoidDataType(type)) { + if (isIndirect) { + return DynamicVariableStorage.INDIRECT_VOID_STORAGE; + } return VariableStorage.VOID_STORAGE; } int sz = type.getLength(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Function.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Function.java index a4437ef4c2..35b490b1f6 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Function.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Function.java @@ -36,9 +36,8 @@ import ghidra.util.task.TaskMonitor; public interface Function extends Namespace { public static final String DEFAULT_PARAM_PREFIX = "param_"; - public static final String THIS_PARAM_NAME = AutoParameterType.THIS.getDisplayName(); - public static final String RETURN_PTR_PARAM_NAME = - AutoParameterType.RETURN_STORAGE_PTR.getDisplayName(); + public static final String THIS_PARAM_NAME = "this"; + public static final String RETURN_PTR_PARAM_NAME = "__return_storage_ptr__"; public static final int DEFAULT_PARAM_PREFIX_LEN = DEFAULT_PARAM_PREFIX.length(); public static final String DEFAULT_LOCAL_PREFIX = "local_"; public static final String DEFAULT_LOCAL_RESERVED_PREFIX = "local_res"; @@ -681,6 +680,7 @@ public interface Function extends Namespace { * a recursive search is generally needed (see {@link #getFunctionThunkAddresses(boolean)}). * This method form may be removed in a future release. */ + @Deprecated public default Address[] getFunctionThunkAddresses() { return getFunctionThunkAddresses(false); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableStorage.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableStorage.java index f314185b5a..e52d9e638a 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableStorage.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableStorage.java @@ -294,8 +294,7 @@ public class VariableStorage implements Comparable { "Variable storage incompatible with program, address space not found: " + curSpace.getName()); } - newVarnodes[i] = - new Varnode(newSpace.getAddress(v[i].getOffset()), v[i].getSize()); + newVarnodes[i] = new Varnode(newSpace.getAddress(v[i].getOffset()), v[i].getSize()); } return new VariableStorage(newProgramArch, newVarnodes); } @@ -625,9 +624,9 @@ public class VariableStorage implements Comparable { if (varnodes == null || otherVarnodes == null) { return false; } - for (int i = 0; i < varnodes.length; i++) { - for (int j = 0; j < otherVarnodes.length; j++) { - if (varnodes[i].intersects(otherVarnodes[j])) { + for (Varnode varnode : varnodes) { + for (Varnode otherVarnode : otherVarnodes) { + if (varnode.intersects(otherVarnode)) { return true; } } @@ -644,8 +643,8 @@ public class VariableStorage implements Comparable { if (varnodes == null || set == null || set.isEmpty()) { return false; } - for (int i = 0; i < varnodes.length; i++) { - if (varnodes[i].intersects(set)) { + for (Varnode varnode : varnodes) { + if (varnode.intersects(set)) { return true; } } @@ -662,8 +661,8 @@ public class VariableStorage implements Comparable { return false; } Varnode regVarnode = new Varnode(reg.getAddress(), reg.getMinimumByteSize()); - for (int i = 0; i < varnodes.length; i++) { - if (varnodes[i].intersects(regVarnode)) { + for (Varnode varnode : varnodes) { + if (varnode.intersects(regVarnode)) { return true; } } @@ -679,8 +678,8 @@ public class VariableStorage implements Comparable { if (varnodes == null) { return false; } - for (int i = 0; i < varnodes.length; i++) { - if (varnodes[i].contains(address)) { + for (Varnode varnode : varnodes) { + if (varnode.contains(address)) { return true; } } @@ -816,8 +815,8 @@ public class VariableStorage implements Comparable { list = null; } if (list == null) { - throw new InvalidInputException("Invalid varnode serialization: '" + serialization + - "'"); + throw new InvalidInputException( + "Invalid varnode serialization: '" + serialization + "'"); } return list; } @@ -869,9 +868,10 @@ public class VariableStorage implements Comparable { if (space.isRegisterSpace()) { long offset = Long.parseUnsignedLong(offsetStr, 16); int size = Integer.parseInt(sizeStr); - Address oldRegAddr = - translator.getOldLanguage().getAddressFactory().getRegisterSpace().getAddress( - offset); + Address oldRegAddr = translator.getOldLanguage() + .getAddressFactory() + .getRegisterSpace() + .getAddress(offset); String newOffsetStr = translateRegisterVarnodeOffset(oldRegAddr, size, translator); if (newOffsetStr != null) { @@ -895,8 +895,8 @@ public class VariableStorage implements Comparable { } if (strBuilder == null) { - throw new InvalidInputException("Invalid varnode serialization: '" + serialization + - "'"); + throw new InvalidInputException( + "Invalid varnode serialization: '" + serialization + "'"); } return strBuilder.toString(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableUtilities.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableUtilities.java index 8a86f81c15..89845b3c5d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableUtilities.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableUtilities.java @@ -163,7 +163,7 @@ public class VariableUtilities { /** * Determine the appropriate data type for an automatic parameter * @param function function whose auto param datatype is to be determined - * @param returnDataType function's return datatype + * @param returnDataType function's formal return datatype * @param storage variable storage for an auto-parameter (isAutoStorage should be true) * @return auto-parameter data type */