From b5a072c25694ca3f33e6b2ed48f8a5ed41ff5f42 Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Mon, 24 Apr 2023 17:43:50 -0400 Subject: [PATCH] GP-3350 revised ApplyFunctionSignatureCmd with new FunctionRenameOption enum --- .../function/ApplyFunctionSignatureCmd.java | 85 +++++++++++-------- .../cmd/function/FunctionRenameOption.java | 44 ++++++++++ .../function/EditFunctionSignatureDialog.java | 3 +- .../app/util/demangler/DemangledFunction.java | 2 +- .../ghidra/app/util/xml/FunctionsXmlMgr.java | 2 +- 5 files changed, 96 insertions(+), 40 deletions(-) create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionRenameOption.java 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 0e01d44b3d..b8b90636af 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 @@ -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 } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionRenameOption.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionRenameOption.java new file mode 100644 index 0000000000..14fce82723 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionRenameOption.java @@ -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; +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/EditFunctionSignatureDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/EditFunctionSignatureDialog.java index ab6e9894d2..416059cbc5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/EditFunctionSignatureDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/EditFunctionSignatureDialog.java @@ -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"); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledFunction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledFunction.java index 0391e06aa1..b8af2e89c2 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledFunction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledFunction.java @@ -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; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/FunctionsXmlMgr.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/FunctionsXmlMgr.java index 9592040821..f27a903d8c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/FunctionsXmlMgr.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/FunctionsXmlMgr.java @@ -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 \"" +