GP-3350 revised ApplyFunctionSignatureCmd with new FunctionRenameOption

enum
This commit is contained in:
ghidra1
2023-04-24 17:43:50 -04:00
parent 8dd584c9bc
commit b5a072c256
5 changed files with 96 additions and 40 deletions
@@ -41,20 +41,22 @@ import ghidra.util.task.TaskMonitor;
public class ApplyFunctionSignatureCmd extends BackgroundCommand { public class ApplyFunctionSignatureCmd extends BackgroundCommand {
private Address entryPt; private Address entryPt;
private SourceType source; private SourceType source;
private boolean setName; private FunctionRenameOption functionRenameOption;
private boolean preserveCallingConvention; private boolean preserveCallingConvention;
private FunctionSignature signature; private FunctionSignature signature;
private Program program; private Program program;
/** /**
* Constructs a new command for creating a function. * Constructs a new command for creating a function.
* Only a function with a default name will be renamed to the function signature's name
* (see {@link FunctionRenameOption#RENAME_IF_DEFAULT}).
* @param entry entry point address for the function to be created. * @param entry entry point address for the function to be created.
* @param signature function signature to apply * @param signature function signature to apply
* @param source the source of this function signature * @param source the source of this function signature
*/ */
public ApplyFunctionSignatureCmd(Address entry, FunctionSignature signature, public ApplyFunctionSignatureCmd(Address entry, FunctionSignature signature,
SourceType source) { SourceType source) {
this(entry, signature, source, false, false); this(entry, signature, source, false, FunctionRenameOption.RENAME_IF_DEFAULT);
} }
/** /**
@@ -63,17 +65,35 @@ public class ApplyFunctionSignatureCmd extends BackgroundCommand {
* @param signature function signature to apply * @param signature function signature to apply
* @param source the source of this function signature * @param source the source of this function signature
* @param preserveCallingConvention if true the function calling convention will not be changed * @param preserveCallingConvention if true the function calling convention will not be changed
* @param setName true if name of the function should be set to the name * @param forceSetName true if name of the function should be set to the name, otherwise name
* of the signature * will only be set name if currently default (e.g., FUN_1234). A value of true is equivalent to
* {@link FunctionRenameOption#RENAME}, while a value of false is equivalent to
* {@link FunctionRenameOption#RENAME_IF_DEFAULT}.
*/
@Deprecated(since = "10.3", forRemoval = true)
public ApplyFunctionSignatureCmd(Address entry, FunctionSignature signature, SourceType source,
boolean preserveCallingConvention, boolean forceSetName) {
this(entry, signature, source, preserveCallingConvention,
forceSetName ? FunctionRenameOption.RENAME : FunctionRenameOption.RENAME_IF_DEFAULT);
}
/**
* Constructs a new command for creating a function.
* @param entry entry point address for the function to be created.
* @param signature function signature to apply
* @param source the source of this function signature
* @param preserveCallingConvention if true the function calling convention will not be changed
* @param functionRenameOption controls renaming of the function using the name from the
* specified function signature.
*/ */
public ApplyFunctionSignatureCmd(Address entry, FunctionSignature signature, SourceType source, public ApplyFunctionSignatureCmd(Address entry, FunctionSignature signature, SourceType source,
boolean preserveCallingConvention, boolean setName) { boolean preserveCallingConvention, FunctionRenameOption functionRenameOption) {
super("Create Function", true, false, false); super("Create Function", true, false, false);
this.entryPt = entry; this.entryPt = entry;
this.signature = signature; this.signature = signature;
this.source = source; this.source = source;
this.preserveCallingConvention = preserveCallingConvention; this.preserveCallingConvention = preserveCallingConvention;
this.setName = setName; this.functionRenameOption = functionRenameOption;
} }
@Override @Override
@@ -89,7 +109,7 @@ public class ApplyFunctionSignatureCmd extends BackgroundCommand {
monitor.setMessage("Rename " + func.getName()); monitor.setMessage("Rename " + func.getName());
try { try {
setSignature(func, signature, preserveCallingConvention, setName, source); setSignature(func);
} }
catch (InvalidInputException e) { catch (InvalidInputException e) {
Msg.warn(this, e.getMessage()); Msg.warn(this, e.getMessage());
@@ -106,22 +126,14 @@ public class ApplyFunctionSignatureCmd extends BackgroundCommand {
} }
/** /**
* Sets a function's signature in the program. * Sets a function's signature in the program using the command details.
* @param func the function * @param func the function
* @param signature the signature to apply
* @param preserveCallingConvention if true, the functions calling convention will not be
* modified
* @param forceName force the name of the signature onto the function
* normally the name is only set on default function names (not user-defined).
* @param source the source of this function signature
*/ */
private boolean setSignature(Function func, FunctionSignature signature, private boolean setSignature(Function func) throws InvalidInputException {
boolean preserveCallingConvention, boolean forceName, SourceType source)
throws InvalidInputException {
// take on the signatures name if this is not a user defined symbol // take on the signatures name if this is not a user defined symbol
String name = signature.getName(); String name = signature.getName();
setName(func, name, source, forceName); setName(func, name);
CompilerSpec compilerSpec = program.getCompilerSpec(); CompilerSpec compilerSpec = program.getCompilerSpec();
String conventionName = getCallingConvention(func, compilerSpec); String conventionName = getCallingConvention(func, compilerSpec);
@@ -293,37 +305,38 @@ public class ApplyFunctionSignatureCmd extends BackgroundCommand {
} }
} }
private static void setName(Function function, String name, SourceType source, /**
boolean forceName) throws InvalidInputException { *
* @param function function to be renamed
* @param name function name to be applied
* @throws InvalidInputException if invalid name is specified or a duplicate name occurs
*/
private void setName(Function function, String name) throws InvalidInputException {
if (name == null) { if (functionRenameOption == FunctionRenameOption.NO_CHANGE || name == null) {
return; return;
} }
Program program = function.getProgram();
Address entryPoint = function.getEntryPoint();
SymbolUtilities.validateName(name); SymbolUtilities.validateName(name);
if (function.getName().equals(name)) {
SymbolTable symbolTable = program.getSymbolTable();
Symbol sym = symbolTable.getPrimarySymbol(entryPoint);
if (sym == null || sym.getName().equals(name)) {
return; return;
} }
if (!forceName && sym.getSource() != SourceType.DEFAULT) { if (functionRenameOption == FunctionRenameOption.RENAME_IF_DEFAULT &&
function.getSymbol().getSource() != SourceType.DEFAULT) {
// not default and we are not forcing the rename // not default and we are not forcing the rename
return; return;
} }
try { try {
removeCodeSymbol(symbolTable, entryPoint, name, function.getParentNamespace()); removeCodeSymbol(function.getEntryPoint(), name, function.getParentNamespace());
sym.setName(name, source); function.setName(name, source);
} }
catch (DuplicateNameException e) { catch (DuplicateNameException e) {
// unexpected
throw new InvalidInputException( throw new InvalidInputException(
"Function name conflict occurred when applying function signature."); "Function name conflict occurred when applying function signature.");
} }
} }
/** /**
@@ -361,13 +374,11 @@ public class ApplyFunctionSignatureCmd extends BackgroundCommand {
return getUniqueName(symbolTable, function, name); return getUniqueName(symbolTable, function, name);
} }
private static void removeCodeSymbol(SymbolTable symbolTable, Address address, String name, private void removeCodeSymbol(Address address, String name, Namespace namespace) {
Namespace namespace) { SymbolTable symbolTable = program.getSymbolTable();
Symbol otherSym = symbolTable.getSymbol(name, address, namespace); Symbol otherSym = symbolTable.getSymbol(name, address, namespace);
if (otherSym != null) { if (otherSym != null && otherSym.getSymbolType() == SymbolType.LABEL) {
if (otherSym.getSymbolType() == SymbolType.LABEL) { otherSym.delete(); // remove label so function rename may use it
otherSym.delete(); // replace label if function name matches
}
} }
} }
@@ -0,0 +1,44 @@
/* ###
* IP: GHIDRA
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.cmd.function;
import ghidra.program.model.data.FunctionDefinition;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.FunctionSignature;
/**
* Option for controlling the renaming of a {@link Function} when applying a
* {@link FunctionSignature} or {@link FunctionDefinition}.
*
* See {@link ApplyFunctionSignatureCmd}.
*/
public enum FunctionRenameOption {
/**
* {@link #NO_CHANGE} indicates that the current {@link Function} name should be changed.
*/
NO_CHANGE,
/**
* {@link #RENAME_IF_DEFAULT} indicates that the current {@link Function} name should be only
* be changed if it is a default name (e.g., FUN_1234).
*/
RENAME_IF_DEFAULT,
/**
* {@link #RENAME} indicates that the current {@link Function} name should always be changed.
*/
RENAME;
}
@@ -19,6 +19,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import ghidra.app.cmd.function.ApplyFunctionSignatureCmd; import ghidra.app.cmd.function.ApplyFunctionSignatureCmd;
import ghidra.app.cmd.function.FunctionRenameOption;
import ghidra.framework.cmd.Command; import ghidra.framework.cmd.Command;
import ghidra.framework.cmd.CompoundCmd; import ghidra.framework.cmd.CompoundCmd;
import ghidra.framework.model.DomainObject; import ghidra.framework.model.DomainObject;
@@ -175,7 +176,7 @@ public class EditFunctionSignatureDialog extends AbstractEditFunctionSignatureDi
return null; return null;
} }
cmd = new ApplyFunctionSignatureCmd(function.getEntryPoint(), definition, cmd = new ApplyFunctionSignatureCmd(function.getEntryPoint(), definition,
SourceType.USER_DEFINED, true, true); SourceType.USER_DEFINED, true, FunctionRenameOption.RENAME);
} }
CompoundCmd compoundCommand = new CompoundCmd("Update Function Signature"); CompoundCmd compoundCommand = new CompoundCmd("Update Function Signature");
@@ -454,7 +454,7 @@ public class DemangledFunction extends DemangledObject {
} }
ApplyFunctionSignatureCmd cmd = new ApplyFunctionSignatureCmd(function.getEntryPoint(), ApplyFunctionSignatureCmd cmd = new ApplyFunctionSignatureCmd(function.getEntryPoint(),
signature, SourceType.IMPORTED, true, false); signature, SourceType.IMPORTED, true, FunctionRenameOption.RENAME_IF_DEFAULT);
cmd.applyTo(program); cmd.applyTo(program);
return true; return true;
@@ -245,7 +245,7 @@ class FunctionsXmlMgr {
} }
ApplyFunctionSignatureCmd afsCmd = new ApplyFunctionSignatureCmd(func.getEntryPoint(), ApplyFunctionSignatureCmd afsCmd = new ApplyFunctionSignatureCmd(func.getEntryPoint(),
funcDef, SourceType.IMPORTED, false, false); funcDef, SourceType.IMPORTED, false, FunctionRenameOption.RENAME_IF_DEFAULT);
if (!afsCmd.applyTo(program, monitor)) { if (!afsCmd.applyTo(program, monitor)) {
// TODO: continue trying to add local vars after failing to update the function signature? // TODO: continue trying to add local vars after failing to update the function signature?
log.appendMsg("Failed to update function " + funcDesc(func) + " with signature \"" + log.appendMsg("Failed to update function " + funcDesc(func) + " with signature \"" +