GP-4133 improved support for __return_storage_ptr__ param which

transitions return storage to VOID.
This commit is contained in:
ghidra1 2023-12-11 16:01:58 -05:00
parent 867ab256b0
commit 2259379a67
9 changed files with 97 additions and 53 deletions

View file

@ -213,14 +213,14 @@ public class ApplyFunctionSignatureCmd extends BackgroundCommand {
returnDt = prepareDataType(returnDt, targetDtm, dtCleaner); returnDt = prepareDataType(returnDt, targetDtm, dtCleaner);
} }
List<Parameter> params = createParameters(compilerSpec, conventionName, args); ReturnParameterImpl returnParam = new ReturnParameterImpl(returnDt, program);
List<Parameter> params =
createParameters(compilerSpec, conventionName, args, returnParam);
SymbolTable symbolTable = program.getSymbolTable(); SymbolTable symbolTable = program.getSymbolTable();
adjustParameterNamesToAvoidConflicts(symbolTable, func, params); adjustParameterNamesToAvoidConflicts(symbolTable, func, params);
ReturnParameterImpl returnParam = new ReturnParameterImpl(returnDt, program);
func.updateFunction(conventionName, returnParam, params, func.updateFunction(conventionName, returnParam, params,
FunctionUpdateType.DYNAMIC_STORAGE_FORMAL_PARAMS, false, source); FunctionUpdateType.DYNAMIC_STORAGE_FORMAL_PARAMS, false, source);
func.setVarArgs(signature.hasVarArgs()); func.setVarArgs(signature.hasVarArgs());
@ -247,7 +247,9 @@ public class ApplyFunctionSignatureCmd extends BackgroundCommand {
} }
private List<Parameter> createParameters(CompilerSpec compilerSpec, String conventionName, private List<Parameter> createParameters(CompilerSpec compilerSpec, String conventionName,
ParameterDefinition[] args) throws InvalidInputException { ParameterDefinition[] args, Parameter returnParam) throws InvalidInputException {
DataType returnDt = returnParam.getDataType();
int firstParamIndex = getIndexOfFirstParameter(conventionName, args); int firstParamIndex = getIndexOfFirstParameter(conventionName, args);
@ -256,11 +258,15 @@ public class ApplyFunctionSignatureCmd extends BackgroundCommand {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
for (int i = firstParamIndex; i < args.length; i++) { for (int i = firstParamIndex; i < args.length; i++) {
String name = args[i].getName(); String name = args[i].getName();
DataType type = args[i].getDataType().clone(dtm);
if (Function.RETURN_PTR_PARAM_NAME.equals(name)) { 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) { if (settleCTypes) {
type = settleCDataType(type, dtm); type = settleCDataType(type, dtm);
} }
@ -269,6 +275,7 @@ public class ApplyFunctionSignatureCmd extends BackgroundCommand {
param.setComment(args[i].getComment()); param.setComment(args[i].getComment());
params.add(param); params.add(param);
} }
return params; return params;
} }

View file

@ -54,10 +54,10 @@ class ParameterDB extends VariableDB implements Parameter {
@Override @Override
public DataType getDataType() { public DataType getDataType() {
DataType dt = getFormalDataType(); DataType dt = getFormalDataType();
VariableStorage varStorage = getVariableStorage(); if (isForcedIndirect()) {
if (varStorage.isForcedIndirect()) {
Program program = function.getProgram(); Program program = function.getProgram();
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
VariableStorage varStorage = getVariableStorage();
int ptrSize = varStorage.size(); int ptrSize = varStorage.size();
if (ptrSize != dtm.getDataOrganization().getPointerSize()) { if (ptrSize != dtm.getDataOrganization().getPointerSize()) {
dt = dtm.getPointer(dt, ptrSize); dt = dtm.getPointer(dt, ptrSize);

View file

@ -18,6 +18,7 @@ package ghidra.program.database.function;
import java.io.IOException; import java.io.IOException;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.lang.DynamicVariableStorage;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.SourceType; import ghidra.program.model.symbol.SourceType;
import ghidra.program.util.ChangeManager; import ghidra.program.util.ChangeManager;
@ -45,8 +46,8 @@ public class ReturnParameterDB extends ParameterDB {
} }
@Override @Override
public void setName(String name, SourceType source) throws DuplicateNameException, public void setName(String name, SourceType source)
InvalidInputException { throws DuplicateNameException, InvalidInputException {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@ -81,10 +82,9 @@ public class ReturnParameterDB extends ParameterDB {
newStorage = VariableStorage.UNASSIGNED_STORAGE; newStorage = VariableStorage.UNASSIGNED_STORAGE;
} }
Program program = function.getProgram(); Program program = function.getProgram();
type = type = VariableUtilities.checkDataType(type,
VariableUtilities.checkDataType(type, newStorage.isVoidStorage() || newStorage.isUnassignedStorage(), getLength(),
newStorage.isVoidStorage() || newStorage.isUnassignedStorage(), getLength(), program);
program);
if (!newStorage.isUnassignedStorage()) { if (!newStorage.isUnassignedStorage()) {
newStorage = VariableUtilities.checkStorage(function, newStorage, type, force); newStorage = VariableUtilities.checkStorage(function, newStorage, type, force);
} }
@ -163,6 +163,19 @@ public class ReturnParameterDB extends ParameterDB {
return dataType; 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 @Override
public SourceType getSource() { public SourceType getSource() {
if (dataType == null || Undefined.isUndefined(dataType)) { if (dataType == null || Undefined.isUndefined(dataType)) {

View file

@ -23,9 +23,26 @@ import ghidra.util.exception.InvalidInputException;
public class DynamicVariableStorage extends VariableStorage { public class DynamicVariableStorage extends VariableStorage {
/**
* <code>INDIRECT_VOID_STORAGE</code> 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 AutoParameterType autoParamType;
private boolean forcedIndirect; private boolean forcedIndirect;
private boolean isUnassigned = false; 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 * Construct Unassigned dynamic variable storage with an optional auto-parameter type
@ -58,8 +75,7 @@ public class DynamicVariableStorage extends VariableStorage {
* @throws InvalidInputException * @throws InvalidInputException
*/ */
public DynamicVariableStorage(ProgramArchitecture program, AutoParameterType autoParamType, public DynamicVariableStorage(ProgramArchitecture program, AutoParameterType autoParamType,
Address address, Address address, int size) throws InvalidInputException {
int size) throws InvalidInputException {
super(program, address, size); super(program, address, size);
this.autoParamType = autoParamType; this.autoParamType = autoParamType;
} }
@ -72,8 +88,7 @@ public class DynamicVariableStorage extends VariableStorage {
* @throws InvalidInputException if specified varnodes violate storage restrictions * @throws InvalidInputException if specified varnodes violate storage restrictions
*/ */
public DynamicVariableStorage(ProgramArchitecture program, AutoParameterType autoParamType, public DynamicVariableStorage(ProgramArchitecture program, AutoParameterType autoParamType,
Varnode... varnodes) Varnode... varnodes) throws InvalidInputException {
throws InvalidInputException {
super(program, varnodes); super(program, varnodes);
this.autoParamType = autoParamType; this.autoParamType = autoParamType;
} }
@ -88,8 +103,7 @@ public class DynamicVariableStorage extends VariableStorage {
* @throws InvalidInputException * @throws InvalidInputException
*/ */
public DynamicVariableStorage(ProgramArchitecture program, boolean forcedIndirect, public DynamicVariableStorage(ProgramArchitecture program, boolean forcedIndirect,
Address address, int size) Address address, int size) throws InvalidInputException {
throws InvalidInputException {
super(program, address, size); super(program, address, size);
this.forcedIndirect = forcedIndirect; this.forcedIndirect = forcedIndirect;
} }
@ -103,8 +117,7 @@ public class DynamicVariableStorage extends VariableStorage {
* @throws InvalidInputException if specified varnodes violate storage restrictions * @throws InvalidInputException if specified varnodes violate storage restrictions
*/ */
public DynamicVariableStorage(ProgramArchitecture program, boolean forcedIndirect, public DynamicVariableStorage(ProgramArchitecture program, boolean forcedIndirect,
Varnode... varnodes) Varnode... varnodes) throws InvalidInputException {
throws InvalidInputException {
super(program, varnodes); super(program, varnodes);
this.forcedIndirect = forcedIndirect; this.forcedIndirect = forcedIndirect;
} }
@ -124,6 +137,11 @@ public class DynamicVariableStorage extends VariableStorage {
return isUnassigned; return isUnassigned;
} }
@Override
public boolean isVoidStorage() {
return isVoid;
}
@Override @Override
public AutoParameterType getAutoParameterType() { public AutoParameterType getAutoParameterType() {
return autoParamType; return autoParamType;
@ -132,7 +150,7 @@ public class DynamicVariableStorage extends VariableStorage {
@Override @Override
public String toString() { public String toString() {
String str = super.toString(); String str = super.toString();
if (forcedIndirect) { if (forcedIndirect && varnodes != null) {
str = str + " (ptr)"; str = str + " (ptr)";
} }
if (autoParamType != null) { if (autoParamType != null) {
@ -146,8 +164,10 @@ public class DynamicVariableStorage extends VariableStorage {
* NOTE: The {@link #isUnassignedStorage()} method should be used to * NOTE: The {@link #isUnassignedStorage()} method should be used to
* detect this type of storage. * detect this type of storage.
* @param autoParamType auto-parameter type or null if not applicable * @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); return new DynamicVariableStorage(autoParamType);
} }
@ -157,6 +177,7 @@ public class DynamicVariableStorage extends VariableStorage {
* detect this type of storage. * detect this type of storage.
* @param forcedIndirect if true indicates that the parameter has been forced to pass * @param forcedIndirect if true indicates that the parameter has been forced to pass
* as a pointer instead of its raw type * as a pointer instead of its raw type
* @return Unassigned dynamic variable storage
*/ */
public static DynamicVariableStorage getUnassignedDynamicStorage(boolean forcedIndirect) { public static DynamicVariableStorage getUnassignedDynamicStorage(boolean forcedIndirect) {
return new DynamicVariableStorage(forcedIndirect); return new DynamicVariableStorage(forcedIndirect);

View file

@ -60,8 +60,8 @@ public class ParamListStandardOut extends ParamListStandard {
else { else {
assignAddressFallback(StorageClass.PTR, pointerType, false, status, store); assignAddressFallback(StorageClass.PTR, pointerType, false, status, store);
store.type = pointerType; 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) { if (addAutoParams) {
ParameterPieces hiddenRet = new ParameterPieces(); ParameterPieces hiddenRet = new ParameterPieces();
hiddenRet.type = pointerType; hiddenRet.type = pointerType;

View file

@ -66,6 +66,9 @@ public class ParameterPieces {
type = DataType.DEFAULT; type = DataType.DEFAULT;
} }
if (VoidDataType.isVoidDataType(type)) { if (VoidDataType.isVoidDataType(type)) {
if (isIndirect) {
return DynamicVariableStorage.INDIRECT_VOID_STORAGE;
}
return VariableStorage.VOID_STORAGE; return VariableStorage.VOID_STORAGE;
} }
int sz = type.getLength(); int sz = type.getLength();

View file

@ -36,9 +36,8 @@ import ghidra.util.task.TaskMonitor;
public interface Function extends Namespace { public interface Function extends Namespace {
public static final String DEFAULT_PARAM_PREFIX = "param_"; public static final String DEFAULT_PARAM_PREFIX = "param_";
public static final String THIS_PARAM_NAME = AutoParameterType.THIS.getDisplayName(); public static final String THIS_PARAM_NAME = "this";
public static final String RETURN_PTR_PARAM_NAME = public static final String RETURN_PTR_PARAM_NAME = "__return_storage_ptr__";
AutoParameterType.RETURN_STORAGE_PTR.getDisplayName();
public static final int DEFAULT_PARAM_PREFIX_LEN = DEFAULT_PARAM_PREFIX.length(); 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_PREFIX = "local_";
public static final String DEFAULT_LOCAL_RESERVED_PREFIX = "local_res"; 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)}). * a recursive search is generally needed (see {@link #getFunctionThunkAddresses(boolean)}).
* This method form may be removed in a future release. * This method form may be removed in a future release.
*/ */
@Deprecated
public default Address[] getFunctionThunkAddresses() { public default Address[] getFunctionThunkAddresses() {
return getFunctionThunkAddresses(false); return getFunctionThunkAddresses(false);
} }

View file

@ -294,8 +294,7 @@ public class VariableStorage implements Comparable<VariableStorage> {
"Variable storage incompatible with program, address space not found: " + "Variable storage incompatible with program, address space not found: " +
curSpace.getName()); curSpace.getName());
} }
newVarnodes[i] = newVarnodes[i] = new Varnode(newSpace.getAddress(v[i].getOffset()), v[i].getSize());
new Varnode(newSpace.getAddress(v[i].getOffset()), v[i].getSize());
} }
return new VariableStorage(newProgramArch, newVarnodes); return new VariableStorage(newProgramArch, newVarnodes);
} }
@ -625,9 +624,9 @@ public class VariableStorage implements Comparable<VariableStorage> {
if (varnodes == null || otherVarnodes == null) { if (varnodes == null || otherVarnodes == null) {
return false; return false;
} }
for (int i = 0; i < varnodes.length; i++) { for (Varnode varnode : varnodes) {
for (int j = 0; j < otherVarnodes.length; j++) { for (Varnode otherVarnode : otherVarnodes) {
if (varnodes[i].intersects(otherVarnodes[j])) { if (varnode.intersects(otherVarnode)) {
return true; return true;
} }
} }
@ -644,8 +643,8 @@ public class VariableStorage implements Comparable<VariableStorage> {
if (varnodes == null || set == null || set.isEmpty()) { if (varnodes == null || set == null || set.isEmpty()) {
return false; return false;
} }
for (int i = 0; i < varnodes.length; i++) { for (Varnode varnode : varnodes) {
if (varnodes[i].intersects(set)) { if (varnode.intersects(set)) {
return true; return true;
} }
} }
@ -662,8 +661,8 @@ public class VariableStorage implements Comparable<VariableStorage> {
return false; return false;
} }
Varnode regVarnode = new Varnode(reg.getAddress(), reg.getMinimumByteSize()); Varnode regVarnode = new Varnode(reg.getAddress(), reg.getMinimumByteSize());
for (int i = 0; i < varnodes.length; i++) { for (Varnode varnode : varnodes) {
if (varnodes[i].intersects(regVarnode)) { if (varnode.intersects(regVarnode)) {
return true; return true;
} }
} }
@ -679,8 +678,8 @@ public class VariableStorage implements Comparable<VariableStorage> {
if (varnodes == null) { if (varnodes == null) {
return false; return false;
} }
for (int i = 0; i < varnodes.length; i++) { for (Varnode varnode : varnodes) {
if (varnodes[i].contains(address)) { if (varnode.contains(address)) {
return true; return true;
} }
} }
@ -816,8 +815,8 @@ public class VariableStorage implements Comparable<VariableStorage> {
list = null; list = null;
} }
if (list == null) { if (list == null) {
throw new InvalidInputException("Invalid varnode serialization: '" + serialization + throw new InvalidInputException(
"'"); "Invalid varnode serialization: '" + serialization + "'");
} }
return list; return list;
} }
@ -869,9 +868,10 @@ public class VariableStorage implements Comparable<VariableStorage> {
if (space.isRegisterSpace()) { if (space.isRegisterSpace()) {
long offset = Long.parseUnsignedLong(offsetStr, 16); long offset = Long.parseUnsignedLong(offsetStr, 16);
int size = Integer.parseInt(sizeStr); int size = Integer.parseInt(sizeStr);
Address oldRegAddr = Address oldRegAddr = translator.getOldLanguage()
translator.getOldLanguage().getAddressFactory().getRegisterSpace().getAddress( .getAddressFactory()
offset); .getRegisterSpace()
.getAddress(offset);
String newOffsetStr = String newOffsetStr =
translateRegisterVarnodeOffset(oldRegAddr, size, translator); translateRegisterVarnodeOffset(oldRegAddr, size, translator);
if (newOffsetStr != null) { if (newOffsetStr != null) {
@ -895,8 +895,8 @@ public class VariableStorage implements Comparable<VariableStorage> {
} }
if (strBuilder == null) { if (strBuilder == null) {
throw new InvalidInputException("Invalid varnode serialization: '" + serialization + throw new InvalidInputException(
"'"); "Invalid varnode serialization: '" + serialization + "'");
} }
return strBuilder.toString(); return strBuilder.toString();

View file

@ -163,7 +163,7 @@ public class VariableUtilities {
/** /**
* Determine the appropriate data type for an automatic parameter * Determine the appropriate data type for an automatic parameter
* @param function function whose auto param datatype is to be determined * @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) * @param storage variable storage for an auto-parameter (isAutoStorage should be true)
* @return auto-parameter data type * @return auto-parameter data type
*/ */