Merge branch 'GP-3350_ghidra1_ReviseApplyFunctionSignatureCmd'

This commit is contained in:
ghidra1 2023-04-27 01:00:36 -04:00
commit f862cdd93d
5 changed files with 96 additions and 40 deletions

View File

@ -41,20 +41,22 @@ import ghidra.util.task.TaskMonitor;
public class ApplyFunctionSignatureCmd extends BackgroundCommand {
private Address entryPt;
private SourceType source;
private boolean setName;
private FunctionRenameOption functionRenameOption;
private boolean preserveCallingConvention;
private FunctionSignature signature;
private Program program;
/**
* 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 signature function signature to apply
* @param source the source of this function signature
*/
public ApplyFunctionSignatureCmd(Address entry, FunctionSignature signature,
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 source the source of this function signature
* @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
* of the signature
* @param forceSetName true if name of the function should be set to the name, otherwise name
* 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,
boolean preserveCallingConvention, boolean setName) {
boolean preserveCallingConvention, FunctionRenameOption functionRenameOption) {
super("Create Function", true, false, false);
this.entryPt = entry;
this.signature = signature;
this.source = source;
this.preserveCallingConvention = preserveCallingConvention;
this.setName = setName;
this.functionRenameOption = functionRenameOption;
}
@Override
@ -89,7 +109,7 @@ public class ApplyFunctionSignatureCmd extends BackgroundCommand {
monitor.setMessage("Rename " + func.getName());
try {
setSignature(func, signature, preserveCallingConvention, setName, source);
setSignature(func);
}
catch (InvalidInputException e) {
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 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,
boolean preserveCallingConvention, boolean forceName, SourceType source)
throws InvalidInputException {
private boolean setSignature(Function func) throws InvalidInputException {
// take on the signatures name if this is not a user defined symbol
String name = signature.getName();
setName(func, name, source, forceName);
setName(func, name);
CompilerSpec compilerSpec = program.getCompilerSpec();
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;
}
Program program = function.getProgram();
Address entryPoint = function.getEntryPoint();
SymbolUtilities.validateName(name);
SymbolTable symbolTable = program.getSymbolTable();
Symbol sym = symbolTable.getPrimarySymbol(entryPoint);
if (sym == null || sym.getName().equals(name)) {
if (function.getName().equals(name)) {
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
return;
}
try {
removeCodeSymbol(symbolTable, entryPoint, name, function.getParentNamespace());
sym.setName(name, source);
removeCodeSymbol(function.getEntryPoint(), name, function.getParentNamespace());
function.setName(name, source);
}
catch (DuplicateNameException e) {
// unexpected
throw new InvalidInputException(
"Function name conflict occurred when applying function signature.");
}
}
/**
@ -361,13 +374,11 @@ public class ApplyFunctionSignatureCmd extends BackgroundCommand {
return getUniqueName(symbolTable, function, name);
}
private static void removeCodeSymbol(SymbolTable symbolTable, Address address, String name,
Namespace namespace) {
private void removeCodeSymbol(Address address, String name, Namespace namespace) {
SymbolTable symbolTable = program.getSymbolTable();
Symbol otherSym = symbolTable.getSymbol(name, address, namespace);
if (otherSym != null) {
if (otherSym.getSymbolType() == SymbolType.LABEL) {
otherSym.delete(); // replace label if function name matches
}
if (otherSym != null && otherSym.getSymbolType() == SymbolType.LABEL) {
otherSym.delete(); // remove label so function rename may use it
}
}

View File

@ -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;
}

View File

@ -19,6 +19,7 @@ import java.util.ArrayList;
import java.util.List;
import ghidra.app.cmd.function.ApplyFunctionSignatureCmd;
import ghidra.app.cmd.function.FunctionRenameOption;
import ghidra.framework.cmd.Command;
import ghidra.framework.cmd.CompoundCmd;
import ghidra.framework.model.DomainObject;
@ -175,7 +176,7 @@ public class EditFunctionSignatureDialog extends AbstractEditFunctionSignatureDi
return null;
}
cmd = new ApplyFunctionSignatureCmd(function.getEntryPoint(), definition,
SourceType.USER_DEFINED, true, true);
SourceType.USER_DEFINED, true, FunctionRenameOption.RENAME);
}
CompoundCmd compoundCommand = new CompoundCmd("Update Function Signature");

View File

@ -454,7 +454,7 @@ public class DemangledFunction extends DemangledObject {
}
ApplyFunctionSignatureCmd cmd = new ApplyFunctionSignatureCmd(function.getEntryPoint(),
signature, SourceType.IMPORTED, true, false);
signature, SourceType.IMPORTED, true, FunctionRenameOption.RENAME_IF_DEFAULT);
cmd.applyTo(program);
return true;

View File

@ -245,7 +245,7 @@ class FunctionsXmlMgr {
}
ApplyFunctionSignatureCmd afsCmd = new ApplyFunctionSignatureCmd(func.getEntryPoint(),
funcDef, SourceType.IMPORTED, false, false);
funcDef, SourceType.IMPORTED, false, FunctionRenameOption.RENAME_IF_DEFAULT);
if (!afsCmd.applyTo(program, monitor)) {
// TODO: continue trying to add local vars after failing to update the function signature?
log.appendMsg("Failed to update function " + funcDesc(func) + " with signature \"" +