diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/editor/DataTypeEditorManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/editor/DataTypeEditorManager.java
index 2743e42c38..e52ef5cd58 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/editor/DataTypeEditorManager.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/editor/DataTypeEditorManager.java
@@ -18,25 +18,21 @@ package ghidra.app.plugin.core.datamgr.editor;
import java.util.ArrayList;
import java.util.List;
-import javax.swing.ComboBoxModel;
-import javax.swing.JPanel;
-
import docking.ComponentProvider;
import docking.actions.DockingToolActions;
import docking.actions.SharedDockingActionPlaceholder;
-import docking.widgets.checkbox.GCheckBox;
-import docking.widgets.combobox.GhidraComboBox;
-import docking.widgets.label.GLabel;
import ghidra.app.plugin.core.compositeeditor.*;
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
-import ghidra.app.plugin.core.function.EditFunctionSignatureDialog;
+import ghidra.app.plugin.core.function.AbstractEditFunctionSignatureDialog;
import ghidra.framework.model.DomainObject;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.data.*;
import ghidra.program.model.data.Enum;
-import ghidra.program.model.listing.*;
+import ghidra.program.model.listing.FunctionSignature;
+import ghidra.program.model.listing.Program;
import ghidra.util.*;
-import ghidra.util.exception.*;
+import ghidra.util.exception.CancelledException;
+import ghidra.util.exception.DuplicateNameException;
/**
* Manages program and archive data type editors.
@@ -238,8 +234,8 @@ public class DataTypeEditorManager
list.add(editor);
}
}
- for (int i = 0; i < list.size(); i++) {
- dismissEditor(list.get(i));
+ for (EditorProvider element : list) {
+ dismissEditor(element);
}
}
@@ -519,55 +515,10 @@ public class DataTypeEditorManager
editFunctionSignature(category, functionDefinition);
}
- private void editFunctionSignature(final Category category,
- final FunctionDefinition functionDefinition) {
-
- Function function =
- new UndefinedFunction(plugin.getProgram(), plugin.getProgram().getMinAddress()) {
- @Override
- public String getCallingConventionName() {
- if (functionDefinition == null) {
- return super.getCallingConventionName();
- }
- return functionDefinition.getGenericCallingConvention().toString();
- }
-
- @Override
- public void setCallingConvention(String name) throws InvalidInputException {
- // no-op; we handle this in the editor dialog
- }
-
- @Override
- public void setInline(boolean isInline) {
- // can't edit this from the DataTypeManager
- }
-
- @Override
- public void setNoReturn(boolean hasNoReturn) {
- // can't edit this from the DataTypeManager
- }
-
- @Override
- public FunctionSignature getSignature() {
- if (functionDefinition != null) {
- return functionDefinition;
- }
- return super.getSignature();
- }
-
- @Override
- public String getName() {
- if (functionDefinition != null) {
- return functionDefinition.getName();
- }
- return "newFunction";
- }
- };
-
- // DT how do I do the same as the other creates.
+ private void editFunctionSignature(Category category, FunctionDefinition functionDefinition) {
PluginTool tool = plugin.getTool();
DTMEditFunctionSignatureDialog editSigDialog = new DTMEditFunctionSignatureDialog(
- plugin.getTool(), "Edit Function Signature", function, category, functionDefinition);
+ plugin.getTool(), "Edit Function Signature", category, functionDefinition);
editSigDialog.setHelpLocation(
new HelpLocation("DataTypeManagerPlugin", "Function_Definition"));
tool.showDialog(editSigDialog);
@@ -577,64 +528,73 @@ public class DataTypeEditorManager
// Inner Classes
//==================================================================================================
- private class DTMEditFunctionSignatureDialog extends EditFunctionSignatureDialog {
+ /**
+ * DTMEditFunctionSignatureDialog provides the ability to edit the
+ * function signature associated with a specific {@link FunctionDefinition}.
+ * Use of this editor requires the presence of the tool-based datatype manager service.
+ */
+ private class DTMEditFunctionSignatureDialog extends AbstractEditFunctionSignatureDialog {
+ private final FunctionDefinition functionDefinition;
+ private final FunctionSignature oldSignature;
private final Category category;
- private final FunctionDefinition functionDefinitionDataType;
- DTMEditFunctionSignatureDialog(PluginTool pluginTool, String title, Function function,
- Category category, FunctionDefinition functionDefinition) {
- super(pluginTool, title, function);
+ DTMEditFunctionSignatureDialog(PluginTool pluginTool, String title, Category category,
+ FunctionDefinition functionDefinition) {
+ super(pluginTool, title, false, false, false);
+ this.functionDefinition = functionDefinition;
this.category = category;
- this.functionDefinitionDataType = functionDefinition;
-
- if (functionDefinitionDataType != null) {
- setCallingConvention(
- functionDefinitionDataType.getGenericCallingConvention().toString());
- }
+ this.oldSignature = buildSignature();
}
- @Override
- protected void installCallingConventionWidget(JPanel parentPanel) {
- callingConventionComboBox = new GhidraComboBox<>();
- GenericCallingConvention[] values = GenericCallingConvention.values();
- String[] choices = new String[values.length];
- for (int i = 0; i < values.length; i++) {
- choices[i] = values[i].toString();
- }
-
- setCallingConventionChoices(choices);
- parentPanel.add(new GLabel("Calling Convention:"));
- parentPanel.add(callingConventionComboBox);
- }
-
- @Override
- protected void installInlineWidget(JPanel parentPanel) {
- inlineCheckBox = new GCheckBox("Inline");
- }
-
- @Override
- protected void installNoReturnWidget(JPanel parentPanel) {
- noReturnCheckBox = new GCheckBox("No Return");
- }
-
- @Override
- protected void installCallFixupWidget(JPanel parentPanel) {
- // don't add this panel
- }
-
- @Override
- protected void setCallingConvention(String callingConvention) {
- ComboBoxModel> model = callingConventionComboBox.getModel();
- int size = model.getSize();
- for (int i = 0; i < size; i++) {
- Object item = model.getElementAt(i);
- if (item.equals(callingConvention)) {
- callingConventionComboBox.setSelectedItem(callingConvention);
- return;
+ private FunctionSignature buildSignature() {
+ if (functionDefinition != null) {
+ if (category.getDataTypeManager() != functionDefinition.getDataTypeManager()) {
+ throw new IllegalArgumentException(
+ "functionDefinition and category must have same Datatypemanager");
}
+ return functionDefinition;
}
+ return new FunctionDefinitionDataType("newFunction");
+ }
- callingConventionComboBox.setSelectedItem(GenericCallingConvention.unknown);
+ @Override
+ protected String[] getSupportedCallFixupNames() {
+ return null; // Call fixup not supported on FunctionDefinition
+ }
+
+ @Override
+ protected String getCallFixupName() {
+ return null; // Call fixup not supported on FunctionDefinition
+ }
+
+ @Override
+ protected FunctionSignature getFunctionSignature() {
+ return oldSignature;
+ }
+
+ @Override
+ protected String getPrototypeString() {
+ return getFunctionSignature().getPrototypeString();
+ }
+
+ @Override
+ protected String getCallingConventionName() {
+ return getFunctionSignature().getGenericCallingConvention().toString();
+ }
+
+ @Override
+ protected List getCallingConventionNames() {
+ GenericCallingConvention[] values = GenericCallingConvention.values();
+ List choices = new ArrayList<>();
+ for (GenericCallingConvention value : values) {
+ choices.add(value.toString());
+ }
+ return choices;
+ }
+
+ @Override
+ protected DataTypeManager getDataTypeManager() {
+ return category.getDataTypeManager();
}
@Override
@@ -657,9 +617,9 @@ public class DataTypeEditorManager
GenericCallingConvention.getGenericCallingConvention(getCallingConvention());
newDefinition.setGenericCallingConvention(callingConvention);
- DataTypeManager manager = category.getDataTypeManager();
+ DataTypeManager manager = getDataTypeManager();
SourceArchive sourceArchive = manager.getLocalSourceArchive();
- if (functionDefinitionDataType == null) {
+ if (functionDefinition == null) {
newDefinition.setSourceArchive(sourceArchive);
newDefinition.setCategoryPath(category.getCategoryPath());
int id = manager.startTransaction("Create Function Definition");
@@ -669,14 +629,14 @@ public class DataTypeEditorManager
else {
int id = manager.startTransaction("Edit Function Definition");
try {
- if (!functionDefinitionDataType.getName().equals(newDefinition.getName())) {
- functionDefinitionDataType.setName(newDefinition.getName());
+ if (!functionDefinition.getName().equals(newDefinition.getName())) {
+ functionDefinition.setName(newDefinition.getName());
}
- functionDefinitionDataType.setArguments(newDefinition.getArguments());
- functionDefinitionDataType.setGenericCallingConvention(
+ functionDefinition.setArguments(newDefinition.getArguments());
+ functionDefinition.setGenericCallingConvention(
newDefinition.getGenericCallingConvention());
- functionDefinitionDataType.setReturnType(newDefinition.getReturnType());
- functionDefinitionDataType.setVarArgs(newDefinition.hasVarArgs());
+ functionDefinition.setReturnType(newDefinition.getReturnType());
+ functionDefinition.setVarArgs(newDefinition.hasVarArgs());
}
catch (InvalidNameException | DuplicateNameException e) {
// not sure why we are squashing this? ...assuming this can't happen
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/AbstractEditFunctionSignatureDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/AbstractEditFunctionSignatureDialog.java
new file mode 100644
index 0000000000..43e106e0f1
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/AbstractEditFunctionSignatureDialog.java
@@ -0,0 +1,435 @@
+/* ###
+ * 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.plugin.core.function;
+
+import java.awt.Component;
+import java.awt.event.ItemEvent;
+import java.util.List;
+
+import javax.swing.*;
+
+import docking.DialogComponentProvider;
+import docking.widgets.checkbox.GCheckBox;
+import docking.widgets.combobox.GhidraComboBox;
+import docking.widgets.label.GDLabel;
+import docking.widgets.label.GLabel;
+import ghidra.app.services.DataTypeManagerService;
+import ghidra.app.util.cparser.C.ParseException;
+import ghidra.app.util.parser.FunctionSignatureParser;
+import ghidra.framework.plugintool.PluginTool;
+import ghidra.program.model.data.DataTypeManager;
+import ghidra.program.model.data.FunctionDefinitionDataType;
+import ghidra.program.model.listing.FunctionSignature;
+import ghidra.util.exception.CancelledException;
+
+/**
+ * EditFunctionSignatureDialog provides an abstract implementation
+ * a function signature editor. Use of this editor requires the presence of the tool-based
+ * datatype manager service.
+ */
+public abstract class AbstractEditFunctionSignatureDialog extends DialogComponentProvider {
+
+ private static final String NONE_CHOICE = "-NONE-";
+ private static int SIGNATURE_COLUMNS = 60;
+
+ protected JLabel signatureLabel;
+ protected JTextField signatureField;
+ protected JComboBox callingConventionComboBox;
+ protected JComboBox callFixupComboBox;
+ protected JCheckBox inlineCheckBox;
+ protected JCheckBox noReturnCheckBox;
+
+ protected boolean allowInLine;
+ protected boolean allowNoReturn;
+ protected boolean allowCallFixup;
+
+ protected PluginTool tool;
+
+ // Due to delayed initialization and tests not actually displaying dialog
+ // we will track function info initialization
+ boolean initialized = false;
+
+ /**
+ * Abstract function signature editor
+ *
+ * @param tool A reference to the active tool.
+ * @param title The title of the dialog.
+ * @param allowInLine true if in-line attribute control should be included
+ * @param allowNoReturn true if no-return attribute control should be added
+ * @param allowCallFixup true if call-fixup choice should be added
+ */
+ public AbstractEditFunctionSignatureDialog(PluginTool tool, String title, boolean allowInLine,
+ boolean allowNoReturn, boolean allowCallFixup) {
+
+ super(title, true, true, true, false);
+ this.tool = tool;
+ this.allowInLine = allowInLine;
+ this.allowNoReturn = allowNoReturn;
+ this.allowCallFixup = allowCallFixup;
+
+ addWorkPanel(buildMainPanel());
+ addOKButton();
+ addCancelButton();
+ setDefaultButton(okButton);
+ setRememberSize(true);
+ }
+
+ @Override
+ public JComponent getComponent() {
+ setFunctionInfo(); //delay update for after construction
+ return super.getComponent();
+ }
+
+ /**
+ * @return DataTypeManager associated with function or function definition
+ */
+ protected abstract DataTypeManager getDataTypeManager();
+
+ /**
+ * @return optional initial function signature which can assist parse with
+ * identifying referenced datatypes within signature
+ */
+ protected abstract FunctionSignature getFunctionSignature();
+
+ /**
+ * @return the initial signature string for the dialog
+ */
+ protected abstract String getPrototypeString();
+
+ /**
+ * @return initial calling convention name
+ */
+ protected abstract String getCallingConventionName();
+
+ /**
+ * @return list of acceptable calling convention names
+ */
+ protected abstract List getCallingConventionNames();
+
+ /**
+ * @return initial in-line attribute value
+ */
+ protected boolean isInline() {
+ return false;
+ }
+
+ /**
+ * @return initial no-return attribute value
+ */
+ protected boolean hasNoReturn() {
+ return false;
+ }
+
+ /**
+ * @return initial call-fixup name or null if n/a
+ */
+ protected abstract String getCallFixupName();
+
+ /**
+ * @return array of allowed call fixup names or null
+ */
+ protected abstract String[] getSupportedCallFixupNames();
+
+ /**
+ * Method must be invoked following construction to fetch function info
+ * and update components.
+ */
+ private void setFunctionInfo() {
+ if (initialized) {
+ return;
+ }
+ initialized = true;
+
+ signatureField.setText(getPrototypeString());
+ setCallingConventionChoices();
+ callingConventionComboBox.setSelectedItem(getCallingConventionName());
+ if (allowInLine) {
+ inlineCheckBox.setSelected(isInline());
+ }
+ if (allowNoReturn) {
+ noReturnCheckBox.setSelected(hasNoReturn());
+ }
+ if (allowCallFixup) {
+ setCallFixupChoices();
+
+ String callFixupName = getCallFixupName();
+ if (callFixupName != null) {
+ callFixupComboBox.setSelectedItem(callFixupName);
+ }
+ }
+ }
+
+ private JPanel buildMainPanel() {
+ JPanel mainPanel = new JPanel();
+ mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+ mainPanel.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 2));
+ mainPanel.add(buildSignaturePanel());
+ mainPanel.add(buildAttributePanel());
+ if (allowCallFixup) {
+ installCallFixupWidget(mainPanel);
+ }
+ return mainPanel;
+ }
+
+ private void installCallFixupWidget(JPanel parentPanel) {
+ JPanel callFixupPanel = buildCallFixupPanel();
+ parentPanel.add(callFixupPanel != null ? callFixupPanel : buildSpacerPanel());
+ }
+
+ private JPanel buildSignaturePanel() {
+ JPanel signaturePanel = new JPanel();
+ signaturePanel.setLayout(new BoxLayout(signaturePanel, BoxLayout.X_AXIS));
+
+ signatureField = new JTextField(SIGNATURE_COLUMNS);
+ signatureLabel = new GDLabel("Signature:");
+ signaturePanel.add(signatureLabel);
+ signaturePanel.add(signatureField);
+
+ signaturePanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+
+ return signaturePanel;
+ }
+
+ private Component buildSpacerPanel() {
+ JPanel panel = new JPanel();
+
+ panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
+ panel.add(Box.createVerticalStrut(20));
+
+ return panel;
+ }
+
+ private JPanel buildAttributePanel() {
+ JPanel attributePanel = new JPanel();
+ attributePanel.setLayout(new BoxLayout(attributePanel, BoxLayout.X_AXIS));
+ attributePanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+
+ installCallingConventionWidget(attributePanel);
+ if (allowInLine) {
+ installInlineWidget(attributePanel);
+ }
+ if (allowNoReturn) {
+ installNoReturnWidget(attributePanel);
+ }
+ attributePanel.add(Box.createGlue());
+
+ return attributePanel;
+ }
+
+ private void installCallingConventionWidget(JPanel parentPanel) {
+ callingConventionComboBox = new GhidraComboBox<>();
+ parentPanel.add(new GLabel("Calling Convention:"));
+ parentPanel.add(callingConventionComboBox);
+ }
+
+ private void installInlineWidget(JPanel parentPanel) {
+ inlineCheckBox = new GCheckBox("Inline");
+ inlineCheckBox.addChangeListener(e -> {
+ if (inlineCheckBox.isSelected() && callFixupComboBox != null) {
+ callFixupComboBox.setSelectedItem(NONE_CHOICE);
+ }
+ });
+ parentPanel.add(inlineCheckBox);
+ }
+
+ private void installNoReturnWidget(JPanel parentPanel) {
+ noReturnCheckBox = new GCheckBox("No Return");
+ parentPanel.add(noReturnCheckBox);
+ }
+
+ private JPanel buildCallFixupPanel() {
+
+ if (allowCallFixup) {
+ return null;
+ }
+
+ JPanel callFixupPanel = new JPanel();
+ callFixupPanel.setLayout(new BoxLayout(callFixupPanel, BoxLayout.X_AXIS));
+
+ callFixupComboBox = new GhidraComboBox<>();
+ callFixupComboBox.addItemListener(e -> {
+ if (e.getStateChange() == ItemEvent.DESELECTED) {
+ return;
+ }
+ if (!NONE_CHOICE.equals(e.getItem())) {
+ inlineCheckBox.setSelected(false);
+ }
+ });
+
+ callFixupPanel.add(new GLabel("Call-Fixup:"));
+ callFixupPanel.add(callFixupComboBox);
+
+ callFixupPanel.add(Box.createGlue());
+ callFixupPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+
+ return callFixupPanel;
+ }
+
+ /**
+ * @return plugin tool for which dialog was constructed
+ */
+ protected PluginTool getTool() {
+ return tool;
+ }
+
+ private String getSignature() {
+ return signatureField.getText();
+ }
+
+ private void setCallingConventionChoices() {
+ callingConventionComboBox.removeAllItems();
+ for (String element : getCallingConventionNames()) {
+ callingConventionComboBox.addItem(element);
+ }
+ }
+
+ /**
+ * @return current calling convention selection from dialog
+ */
+ protected String getCallingConvention() {
+ return (String) callingConventionComboBox.getSelectedItem();
+ }
+
+ /**
+ * @return current in-line attribute value from dialog
+ */
+ protected boolean isInlineSelected() {
+ return inlineCheckBox != null ? inlineCheckBox.isSelected() : false;
+ }
+
+ /**
+ * @return current no-return attribute value from dialog
+ */
+ protected boolean hasNoReturnSelected() {
+ return noReturnCheckBox != null ? noReturnCheckBox.isSelected() : false;
+ }
+
+ private void setCallFixupChoices() {
+ String[] callFixupNames = getSupportedCallFixupNames();
+ callFixupComboBox.addItem(NONE_CHOICE);
+ if (callFixupNames != null) {
+ for (String element : callFixupNames) {
+ callFixupComboBox.addItem(element);
+ }
+ }
+ }
+
+ /**
+ * @return current call fixup selection from dialog or null
+ */
+ protected String getCallFixupSelection() {
+ if (callFixupComboBox != null) {
+ String callFixup = (String) callFixupComboBox.getSelectedItem();
+ if (callFixup != null && !NONE_CHOICE.equals(callFixup)) {
+ return callFixup;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * This method gets called when the user clicks on the OK Button. The base
+ * class calls this method. This method will invoke {@link #applyChanges()}
+ * and close dialog if that method returns true. If false is returned, the
+ * {@link #applyChanges()} method should display a status message to indicate
+ * the failure.
+ */
+ @Override
+ protected void okCallback() {
+ // only close the dialog if the user made valid changes
+ try {
+ if (applyChanges()) {
+ close();
+ }
+ }
+ catch (CancelledException e) {
+ // ignore - do not close
+ }
+ }
+
+ @Override
+ protected void cancelCallback() {
+ setStatusText("");
+ close();
+ }
+
+ /**
+ * Called when the user initiates changes that need to be applied to the
+ * underlying function or function definition
+ *
+ * @return true if applied successfully, otherwise false which will keep
+ * dialog displayed (a status message should bet set)
+ * @throws CancelledException if operation cancelled by user
+ */
+ protected abstract boolean applyChanges() throws CancelledException;
+
+ /**
+ * Perform parse of current user-specified function signature (see {@link #getSignature()})
+ * and return valid {@link FunctionDefinitionDataType} if parse successful.
+ * @return function definition data type if parse successful, otherwise null
+ * @throws CancelledException if function signature entry cancelled
+ */
+ protected final FunctionDefinitionDataType parseSignature() throws CancelledException {
+ setFunctionInfo(); // needed for testing which never shows dialog
+ FunctionSignatureParser parser = new FunctionSignatureParser(
+ getDataTypeManager(), tool.getService(DataTypeManagerService.class));
+ try {
+ // FIXME: Parser returns FunctionDefinition which only supports GenericCallingConventions
+ return parser.parse(getFunctionSignature(), getSignature());
+ }
+ catch (ParseException e) {
+ setStatusText("Invalid Signature: " + e.getMessage());
+ }
+ return null;
+ }
+
+ /**
+ * Determine if user-specified function signature has been modified from original
+ * @return true if modified signature has been entered, else false
+ */
+ protected final boolean isSignatureChanged() {
+ return !getSignature().equals(getPrototypeString());
+ }
+
+ /**
+ * Determine if user has changed the selected calling convention from the original
+ * @return true if a change in the selected calling convention has been made
+ */
+ protected final boolean isCallingConventionChanged() {
+ String current = getCallingConventionName();
+ if (current == null && this.getCallingConvention() == null) {
+ return false;
+ }
+ if (current == null && this.getCallingConvention().equals("default")) {
+ return false;
+ }
+ if (current == null && this.getCallingConvention().equals("unknown")) {
+ return false;
+ }
+ if (current == null) {
+ return true;
+ }
+ if (current.equals(getCallingConvention())) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ protected void dialogShown() {
+ signatureField.selectAll();
+ }
+}
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 dcd4bfdcba..270b9440a7 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
@@ -15,300 +15,122 @@
*/
package ghidra.app.plugin.core.function;
-import java.awt.Component;
-import java.awt.event.ItemEvent;
import java.util.List;
-import javax.swing.*;
-
-import docking.DialogComponentProvider;
-import docking.widgets.checkbox.GCheckBox;
-import docking.widgets.combobox.GhidraComboBox;
-import docking.widgets.label.GDLabel;
-import docking.widgets.label.GLabel;
import ghidra.app.cmd.function.ApplyFunctionSignatureCmd;
-import ghidra.app.services.DataTypeManagerService;
-import ghidra.app.util.cparser.C.ParseException;
-import ghidra.app.util.parser.FunctionSignatureParser;
import ghidra.framework.cmd.Command;
import ghidra.framework.cmd.CompoundCmd;
import ghidra.framework.model.DomainObject;
import ghidra.framework.plugintool.PluginTool;
+import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.FunctionDefinitionDataType;
-import ghidra.program.model.lang.PrototypeModel;
import ghidra.program.model.listing.Function;
-import ghidra.program.model.listing.Program;
+import ghidra.program.model.listing.FunctionSignature;
import ghidra.program.model.symbol.SourceType;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.InvalidInputException;
/**
- * EditFunctionSignatureDialog provides the ability to edit function
- * signatures. Use of this editor requires the presence of the tool-based
- * datatype manager service.
+ * EditFunctionSignatureDialog provides the ability to edit the
+ * function signature associated with a specific {@link Function}.
+ * Use of this editor requires the presence of the tool-based datatype manager service.
*/
-public class EditFunctionSignatureDialog extends DialogComponentProvider {
+public class EditFunctionSignatureDialog extends AbstractEditFunctionSignatureDialog {
- private static final String NONE_CHOICE = "-NONE-";
-
- protected JLabel signatureLabel;
- protected JTextField signatureField;
- protected JComboBox callingConventionComboBox;
- protected JComboBox callFixupComboBox;
- protected JCheckBox inlineCheckBox;
- protected JCheckBox noReturnCheckBox;
-
- protected PluginTool tool;
- protected Function function;
- protected String oldFunctionName;
- protected String oldFunctionSignature;
+ protected final Function function;
+ protected final String oldFunctionSignature;
/**
- * This class is not meant to be instantiated directly, but rather by
- * subclasses.
- *
- * @param plugin A reference to the FunctionPlugin.
+ * Edit function signature for a specified Function
+ * @param tool A reference to the active tool.
* @param title The title of the dialog.
* @param function the function which is having its signature edited.
*/
public EditFunctionSignatureDialog(PluginTool tool, String title, final Function function) {
-
- super(title, true, true, true, false);
- this.tool = tool;
+ super(tool, title, allowInLine(function), true, allowCallFixup(function));
this.function = function;
- this.oldFunctionName = function.getName();
this.oldFunctionSignature = function.getSignature().getPrototypeString();
-
- addWorkPanel(buildMainPanel());
- addOKButton();
- addCancelButton();
- setDefaultButton(okButton);
- setFunctionInfo();
- setRememberSize(true);
}
- protected void setFunctionInfo() {
- setSignature(function.getSignature().getPrototypeString());
- setCallingConvention(function.getCallingConventionName());
- setInlineSelected(function.isInline());
- inlineCheckBox.setEnabled(!getAffectiveFunction(function).isExternal());
- setNoReturnSelected(function.hasNoReturn());
+ protected EditFunctionSignatureDialog(PluginTool tool, String title, final Function function,
+ boolean allowInLine, boolean allowNoReturn, boolean allowCallFixup) {
+ super(tool, title, allowInLine, allowNoReturn, allowCallFixup);
+ this.function = function;
+ this.oldFunctionSignature = function.getSignature().getPrototypeString();
+ }
+
+ @Override
+ protected FunctionSignature getFunctionSignature() {
+ return function.getSignature();
+ }
+
+ @Override
+ protected String getPrototypeString() {
+ return oldFunctionSignature;
+ }
+
+ @Override
+ protected String getCallingConventionName() {
+ return function.getCallingConventionName();
+ }
+
+ @Override
+ protected List getCallingConventionNames() {
+ return function.getProgram().getFunctionManager().getCallingConventionNames();
+ }
+
+ @Override
+ protected boolean isInline() {
+ return function.isInline();
+ }
+
+ @Override
+ protected boolean hasNoReturn() {
+ return function.hasNoReturn();
+ }
+
+ @Override
+ protected String getCallFixupName() {
+ return function.getCallFixup();
+ }
+
+ private static String[] getCallFixupNames(Function function) {
+ String[] callFixupNames =
+ function.getProgram().getCompilerSpec().getPcodeInjectLibrary().getCallFixupNames();
+ if (callFixupNames.length == 0) {
+ return null;
+ }
+ return callFixupNames;
+ }
+
+ @Override
+ protected String[] getSupportedCallFixupNames() {
+ return getCallFixupNames(function);
+ }
+
+ @Override
+ protected DataTypeManager getDataTypeManager() {
+ return function.getProgram().getDataTypeManager();
}
/**
* Get the effective function to which changes will be made. This
* will be the same as function unless it is a thunk in which case
* the returned function will be the ultimate non-thunk function.
- * @param f
+ * @param f function
* @return non-thunk function
*/
- protected Function getAffectiveFunction(Function f) {
+ private static Function getEffectiveFunction(Function f) {
return f.isThunk() ? f.getThunkedFunction(true) : f;
}
- private JPanel buildMainPanel() {
- JPanel mainPanel = new JPanel();
- mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
- mainPanel.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 2));
- mainPanel.add(buildSignaturePanel());
- mainPanel.add(buildAttributePanel());
-
- installCallFixupWidget(mainPanel);
-
- return mainPanel;
+ private static boolean allowInLine(Function function) {
+ return !getEffectiveFunction(function).isExternal();
}
- protected void installCallFixupWidget(JPanel parentPanel) {
- JPanel callFixupPanel = buildCallFixupPanel();
- parentPanel.add(callFixupPanel != null ? callFixupPanel : buildSpacerPanel());
- }
-
- private JPanel buildSignaturePanel() {
- JPanel signaturePanel = new JPanel();
- signaturePanel.setLayout(new BoxLayout(signaturePanel, BoxLayout.X_AXIS));
-
- String signature = function.getPrototypeString(false, false);
- signatureField = new JTextField(signature.length()); // add some extra room to edit
- signatureField.setText(signature);
- signatureLabel = new GDLabel("Signature:");
- signaturePanel.add(signatureLabel);
- signaturePanel.add(signatureField);
-
- signaturePanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
-
- return signaturePanel;
- }
-
- private Component buildSpacerPanel() {
- JPanel panel = new JPanel();
-
- panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
- panel.add(Box.createVerticalStrut(20));
-
- return panel;
- }
-
- private JPanel buildAttributePanel() {
- JPanel attributePanel = new JPanel();
- attributePanel.setLayout(new BoxLayout(attributePanel, BoxLayout.X_AXIS));
- attributePanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
-
- installCallingConventionWidget(attributePanel);
- installInlineWidget(attributePanel);
- installNoReturnWidget(attributePanel);
- attributePanel.add(Box.createGlue());
-
- return attributePanel;
- }
-
- protected void installCallingConventionWidget(JPanel parentPanel) {
- callingConventionComboBox = new GhidraComboBox<>();
- List callingConventions =
- function.getProgram().getFunctionManager().getCallingConventionNames();
- String[] choices = callingConventions.toArray(new String[callingConventions.size()]);
- setCallingConventionChoices(choices);
- parentPanel.add(new GLabel("Calling Convention:"));
- parentPanel.add(callingConventionComboBox);
- }
-
- protected void installInlineWidget(JPanel parentPanel) {
- inlineCheckBox = new GCheckBox("Inline");
- inlineCheckBox.addChangeListener(e -> {
- if (inlineCheckBox.isSelected() && callFixupComboBox != null) {
- callFixupComboBox.setSelectedItem(NONE_CHOICE);
- }
- });
- parentPanel.add(inlineCheckBox);
- }
-
- protected void installNoReturnWidget(JPanel parentPanel) {
- noReturnCheckBox = new GCheckBox("No Return");
- parentPanel.add(noReturnCheckBox);
- }
-
- private JPanel buildCallFixupPanel() {
-
- String[] callFixupNames =
- function.getProgram().getCompilerSpec().getPcodeInjectLibrary().getCallFixupNames();
- if (callFixupNames.length == 0) {
- return null;
- }
-
- JPanel callFixupPanel = new JPanel();
- callFixupPanel.setLayout(new BoxLayout(callFixupPanel, BoxLayout.X_AXIS));
-
- callFixupComboBox = new GhidraComboBox<>();
- callFixupComboBox.addItem(NONE_CHOICE);
- for (String element : callFixupNames) {
- callFixupComboBox.addItem(element);
- }
-
- callFixupComboBox.addItemListener(e -> {
- if (e.getStateChange() == ItemEvent.DESELECTED) {
- return;
- }
- if (!NONE_CHOICE.equals(e.getItem())) {
- inlineCheckBox.setSelected(false);
- }
- });
-
- String callFixupName = function.getCallFixup();
- if (callFixupName != null) {
- callFixupComboBox.setSelectedItem(callFixupName);
- }
-
- callFixupPanel.add(new GLabel("Call-Fixup:"));
- callFixupPanel.add(callFixupComboBox);
-
- callFixupPanel.add(Box.createGlue());
- callFixupPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
-
- return callFixupPanel;
- }
-
- protected PluginTool getTool() {
- return tool;
- }
-
- protected Program getProgram() {
- return function.getProgram();
- }
-
- protected Function getFunction() {
- return function;
- }
-
- public String getSignature() {
- return signatureField.getText();
- }
-
- protected void setSignature(String signature) {
- signatureField.setText(signature);
- }
-
- protected void setCallingConventionChoices(String[] callingConventions) {
- callingConventionComboBox.removeAllItems();
- for (String element : callingConventions) {
- callingConventionComboBox.addItem(element);
- }
- }
-
- protected String getCallingConvention() {
- return (String) callingConventionComboBox.getSelectedItem();
- }
-
- protected void setCallingConvention(String callingConvention) {
- callingConventionComboBox.setSelectedItem(callingConvention);
- }
-
- protected boolean isInlineSelected() {
- return inlineCheckBox.isSelected();
- }
-
- protected void setInlineSelected(boolean selected) {
- inlineCheckBox.setSelected(selected);
- }
-
- protected boolean hasNoReturnSelected() {
- return noReturnCheckBox.isSelected();
- }
-
- protected void setNoReturnSelected(boolean selected) {
- noReturnCheckBox.setSelected(selected);
- }
-
- protected String getCallFixupSelection() {
- if (callFixupComboBox != null) {
- String callFixup = (String) callFixupComboBox.getSelectedItem();
- if (callFixup != null && !NONE_CHOICE.equals(callFixup)) {
- return callFixup;
- }
- }
- return null;
- }
-
- /**
- * This method gets called when the user clicks on the OK Button. The base
- * class calls this method.
- */
- @Override
- protected void okCallback() {
- // only close the dialog if the user made valid changes
- try {
- if (applyChanges()) {
- close();
- }
- }
- catch (CancelledException e) {
- // ignore - do not close
- }
- }
-
- @Override
- protected void cancelCallback() {
- setStatusText("");
- close();
+ private static boolean allowCallFixup(Function function) {
+ return getCallFixupNames(function) != null;
}
/**
@@ -318,6 +140,7 @@ public class EditFunctionSignatureDialog extends DialogComponentProvider {
* @return true if the command was successfully created.
* @throws CancelledException if operation cancelled by user
*/
+ @Override
protected boolean applyChanges() throws CancelledException {
// create the command
Command command = createCommand();
@@ -327,7 +150,7 @@ public class EditFunctionSignatureDialog extends DialogComponentProvider {
}
// run the command
- if (!getTool().execute(command, getProgram())) {
+ if (!getTool().execute(command, function.getProgram())) {
setStatusText(command.getStatusMsg());
return false;
}
@@ -336,25 +159,16 @@ public class EditFunctionSignatureDialog extends DialogComponentProvider {
return true;
}
- protected FunctionDefinitionDataType parseSignature() throws CancelledException {
- FunctionSignatureParser parser = new FunctionSignatureParser(
- getProgram().getDataTypeManager(), tool.getService(DataTypeManagerService.class));
- try {
- return parser.parse(getFunction().getSignature(), getSignature());
- }
- catch (ParseException e) {
- setStatusText("Invalid Signature: " + e.getMessage());
- }
- return null;
- }
-
private Command createCommand() throws CancelledException {
Command cmd = null;
- if (!getSignature().equals(this.oldFunctionSignature) || !isSameCallingConvention() ||
+ if (isSignatureChanged() || isCallingConventionChanged() ||
(function.getSignatureSource() == SourceType.DEFAULT)) {
FunctionDefinitionDataType definition = parseSignature();
+ if (definition == null) {
+ return null;
+ }
cmd = new ApplyFunctionSignatureCmd(function.getEntryPoint(), definition,
SourceType.USER_DEFINED, true, true);
}
@@ -394,85 +208,67 @@ public class EditFunctionSignatureDialog extends DialogComponentProvider {
return errMsg;
}
});
- compoundCommand.add(new Command() {
- @Override
- public boolean applyTo(DomainObject obj) {
- function.setInline(isInlineSelected());
- return true;
- }
+ if (allowInLine) {
+ compoundCommand.add(new Command() {
+ @Override
+ public boolean applyTo(DomainObject obj) {
+ function.setInline(isInlineSelected());
+ return true;
+ }
- @Override
- public String getName() {
- return "Update Function Inline Flag";
- }
+ @Override
+ public String getName() {
+ return "Update Function Inline Flag";
+ }
- @Override
- public String getStatusMsg() {
- return null;
- }
- });
- compoundCommand.add(new Command() {
- @Override
- public boolean applyTo(DomainObject obj) {
- function.setNoReturn(hasNoReturnSelected());
- return true;
- }
+ @Override
+ public String getStatusMsg() {
+ return null;
+ }
+ });
+ }
+ if (allowNoReturn) {
+ compoundCommand.add(new Command() {
+ @Override
+ public boolean applyTo(DomainObject obj) {
+ function.setNoReturn(hasNoReturnSelected());
+ return true;
+ }
- @Override
- public String getName() {
- return "Update Function No Return Flag";
- }
+ @Override
+ public String getName() {
+ return "Update Function No Return Flag";
+ }
- @Override
- public String getStatusMsg() {
- return null;
- }
- });
- compoundCommand.add(new Command() {
- @Override
- public boolean applyTo(DomainObject obj) {
- function.setCallFixup(getCallFixupSelection());
- return true;
- }
+ @Override
+ public String getStatusMsg() {
+ return null;
+ }
+ });
+ }
+ if (allowCallFixup) {
+ compoundCommand.add(new Command() {
+ @Override
+ public boolean applyTo(DomainObject obj) {
+ function.setCallFixup(getCallFixupSelection());
+ return true;
+ }
- @Override
- public String getName() {
- return "Update Function Call-Fixup";
- }
+ @Override
+ public String getName() {
+ return "Update Function Call-Fixup";
+ }
- @Override
- public String getStatusMsg() {
- return null;
- }
- });
+ @Override
+ public String getStatusMsg() {
+ return null;
+ }
+ });
+ }
if (cmd != null) {
compoundCommand.add(cmd);
}
return compoundCommand;
}
- private boolean isSameCallingConvention() {
- PrototypeModel conv = function.getCallingConvention();
- if (conv == null && this.getCallingConvention() == null) {
- return true;
- }
- if (conv == null && this.getCallingConvention().equals("default")) {
- return true;
- }
- if (conv == null && this.getCallingConvention().equals("unknown")) {
- return true;
- }
- if (conv == null) {
- return false;
- }
- if (conv.getName().equals(this.getCallingConvention())) {
- return true;
- }
- return false;
- }
-
- @Override
- protected void dialogShown() {
- signatureField.selectAll();
- }
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/html/FunctionDataTypeHTMLRepresentation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/html/FunctionDataTypeHTMLRepresentation.java
index d2c780c871..ef8083b8fa 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/html/FunctionDataTypeHTMLRepresentation.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/html/FunctionDataTypeHTMLRepresentation.java
@@ -88,7 +88,7 @@ public class FunctionDataTypeHTMLRepresentation extends HTMLDataTypeRepresentati
GenericCallingConvention genericCallingConvention =
functionDefinition.getGenericCallingConvention();
String modifier = genericCallingConvention != GenericCallingConvention.unknown
- ? (" " + genericCallingConvention.name())
+ ? (" " + genericCallingConvention.getDeclarationName())
: "";
return new TextLine(
HTMLUtilities.friendlyEncodeHTML(returnDataType.getDisplayName()) + modifier);
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPluginTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPluginTest.java
index e7adb329df..d91ff9750d 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPluginTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPluginTest.java
@@ -50,7 +50,7 @@ import ghidra.app.plugin.core.datamgr.actions.CreateTypeDefDialog;
import ghidra.app.plugin.core.datamgr.archive.Archive;
import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
import ghidra.app.plugin.core.datamgr.tree.*;
-import ghidra.app.plugin.core.function.EditFunctionSignatureDialog;
+import ghidra.app.plugin.core.function.AbstractEditFunctionSignatureDialog;
import ghidra.app.plugin.core.programtree.ProgramTreePlugin;
import ghidra.app.services.ProgramManager;
import ghidra.app.util.datatype.DataTypeSelectionEditor;
@@ -695,11 +695,9 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe
DataType dt = iter.next();
listTwo.add(dt);
}
- for (int i = 0; i < listOne.size(); i++) {
- DataType dt = listOne.get(i);
+ for (DataType dt : listOne) {
boolean found = false;
- for (int j = 0; j < listTwo.size(); j++) {
- DataType dt2 = listTwo.get(j);
+ for (DataType dt2 : listTwo) {
if (dt.isEquivalent(dt2)) {
found = true;
break;
@@ -807,8 +805,8 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe
assertTrue(action.isEnabledForContext(treeContext));
performAction(action, treeContext, false);
- EditFunctionSignatureDialog dialog =
- waitForDialogComponent(EditFunctionSignatureDialog.class);
+ AbstractEditFunctionSignatureDialog dialog =
+ waitForDialogComponent(AbstractEditFunctionSignatureDialog.class);
JTextField textField = (JTextField) getInstanceField("signatureField", dialog);
setText(textField, newSignature);
diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/OverridePrototypeAction.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/OverridePrototypeAction.java
index 39ddda0173..1d133909e2 100644
--- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/OverridePrototypeAction.java
+++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/OverridePrototypeAction.java
@@ -29,59 +29,12 @@ import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.pcode.*;
import ghidra.program.model.symbol.Reference;
+import ghidra.program.model.symbol.SourceType;
import ghidra.util.*;
import ghidra.util.exception.CancelledException;
public class OverridePrototypeAction extends AbstractDecompilerAction {
- public class ProtoOverrideDialog extends EditFunctionSignatureDialog {
- private FunctionDefinition functionDefinition;
-
- public FunctionDefinition getFunctionDefinition() {
- return functionDefinition;
- }
-
- public ProtoOverrideDialog(PluginTool tool, Function func, String signature, String conv) {
- super(tool, "Override Signature", func);
- setHelpLocation(new HelpLocation(HelpTopics.DECOMPILER, "ActionOverrideSignature"));
- setSignature(signature);
- setCallingConvention(conv);
- }
-
- /**
- * This method gets called when the user clicks on the OK Button. The base
- * class calls this method.
- */
- @Override
- protected void okCallback() {
- // only close the dialog if the user made valid changes
- if (parseFunctionDefinition()) {
- close();
- }
- }
-
- private boolean parseFunctionDefinition() {
-
- functionDefinition = null;
-
- try {
- functionDefinition = parseSignature();
- }
- catch (CancelledException e) {
- // ignore
- }
-
- if (functionDefinition == null) {
- return false;
- }
-
- GenericCallingConvention convention =
- GenericCallingConvention.guessFromName(getCallingConvention());
- functionDefinition.setGenericCallingConvention(convention);
- return true;
- }
- }
-
public OverridePrototypeAction() {
super("Override Signature");
setHelpLocation(new HelpLocation(HelpTopics.DECOMPILER, "ActionOverrideSignature"));
@@ -183,11 +136,30 @@ public class OverridePrototypeAction extends AbstractDecompilerAction {
return null;
}
- private String generateSignature(PcodeOp op, String name) {
+ private String generateSignature(PcodeOp op, String name, Function calledfunc) {
+
+ // TODO: If an override has already be placed-down it should probably be used
+ // for the initial signature. HighFunction does not make it easy to grab
+ // existing override prototype
+
+ if (calledfunc != null) {
+ SourceType signatureSource = calledfunc.getSignatureSource();
+ if (signatureSource == SourceType.DEFAULT || signatureSource == SourceType.ANALYSIS) {
+ calledfunc = null; // ignore
+ }
+ }
+
StringBuffer buf = new StringBuffer();
+
Varnode vn = op.getOutput();
DataType dt = null;
- if (vn != null) {
+ if (calledfunc != null) {
+ dt = calledfunc.getReturnType();
+ if (Undefined.isUndefined(dt)) {
+ dt = null;
+ }
+ }
+ if (dt == null && vn != null) {
dt = vn.getHigh().getDataType();
}
if (dt != null) {
@@ -198,26 +170,48 @@ public class OverridePrototypeAction extends AbstractDecompilerAction {
}
buf.append(' ').append(name).append('(');
- for (int i = 1; i < op.getNumInputs(); ++i) {
- vn = op.getInput(i);
- dt = null;
- if (vn != null) {
- dt = vn.getHigh().getDataType();
- }
- if (dt != null) {
- buf.append(dt.getDisplayName());
- }
- else {
- buf.append("BAD");
- }
- if (i != op.getNumInputs() - 1) {
- buf.append(',');
+
+ int index = 1;
+ if (calledfunc != null) {
+ for (Parameter p : calledfunc.getParameters()) {
+ String dtName = getInputDataTypeName(op, index, p.getDataType());
+ if (index++ != 1) {
+ buf.append(", ");
+ }
+ buf.append(dtName);
+ if (p.getSource() != SourceType.DEFAULT) {
+ buf.append(' ');
+ buf.append(p.getName());
+ }
}
}
+
+ for (int i = index; i < op.getNumInputs(); ++i) {
+ if (i != 1) {
+ buf.append(", ");
+ }
+ buf.append(getInputDataTypeName(op, i, null));
+ }
+
buf.append(')');
return buf.toString();
}
+ private String getInputDataTypeName(PcodeOp op, int inIndex, DataType preferredDt) {
+ if (preferredDt != null && !Undefined.isUndefined(preferredDt)) {
+ return preferredDt.getDisplayName();
+ }
+ Varnode vn = op.getInput(inIndex);
+ DataType dt = null;
+ if (vn != null) {
+ dt = vn.getHigh().getDataType();
+ }
+ if (dt != null) {
+ return dt.getDisplayName();
+ }
+ return "BAD";
+ }
+
@Override
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
Function function = context.getFunction();
@@ -257,9 +251,10 @@ public class OverridePrototypeAction extends AbstractDecompilerAction {
conv = calledfunc.getCallingConventionName();
}
- String signature = generateSignature(op, name);
+ String signature = generateSignature(op, name, calledfunc);
PluginTool tool = context.getTool();
- ProtoOverrideDialog dialog = new ProtoOverrideDialog(tool, func, signature, conv);
+ ProtoOverrideDialog dialog =
+ new ProtoOverrideDialog(tool, calledfunc != null ? calledfunc : func, signature, conv);
tool.showDialog(dialog);
FunctionDefinition fdef = dialog.getFunctionDefinition();
if (fdef == null) {
@@ -279,4 +274,71 @@ public class OverridePrototypeAction extends AbstractDecompilerAction {
program.endTransaction(transaction, commit);
}
}
+
+ /**
+ * ProtoOverrideDialog provides the ability to edit the
+ * function signature associated with a specific function definition override
+ * at a sub-function callsite.
+ * Use of this editor requires the presence of the tool-based datatype manager service.
+ */
+ private class ProtoOverrideDialog extends EditFunctionSignatureDialog {
+ private FunctionDefinition functionDefinition;
+ private final String initialSignature;
+ private final String initialConvention;
+
+ /**
+ * Construct signature override for called function
+ * @param tool active tool
+ * @param func function from which program access is achieved and supply of preferred
+ * datatypes when parsing signature
+ * @param signature initial prototype signature to be used
+ * @param conv initial calling convention
+ */
+ public ProtoOverrideDialog(PluginTool tool, Function func, String signature, String conv) {
+ super(tool, "Override Signature", func, false, false, false);
+ setHelpLocation(new HelpLocation(HelpTopics.DECOMPILER, "ActionOverrideSignature"));
+ this.initialSignature = signature;
+ this.initialConvention = conv;
+ }
+
+ @Override
+ protected String getPrototypeString() {
+ return initialSignature;
+ }
+
+ @Override
+ protected String getCallingConventionName() {
+ return initialConvention;
+ }
+
+ @Override
+ protected boolean applyChanges() throws CancelledException {
+ return parseFunctionDefinition();
+ }
+
+ private boolean parseFunctionDefinition() {
+
+ functionDefinition = null;
+
+ try {
+ functionDefinition = parseSignature();
+ }
+ catch (CancelledException e) {
+ // ignore
+ }
+
+ if (functionDefinition == null) {
+ return false;
+ }
+
+ GenericCallingConvention convention =
+ GenericCallingConvention.guessFromName(getCallingConvention());
+ functionDefinition.setGenericCallingConvention(convention);
+ return true;
+ }
+
+ public FunctionDefinition getFunctionDefinition() {
+ return functionDefinition;
+ }
+ }
}