mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-10 12:19:23 +08:00
GP-356 refactor of EditFunctionSignatureDialog and the various
extensions.
This commit is contained in:
+76
-116
@@ -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 {
|
||||
/**
|
||||
* <code>DTMEditFunctionSignatureDialog</code> 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<String> getCallingConventionNames() {
|
||||
GenericCallingConvention[] values = GenericCallingConvention.values();
|
||||
List<String> 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
|
||||
|
||||
+435
@@ -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;
|
||||
|
||||
/**
|
||||
* <code>EditFunctionSignatureDialog</code> 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<String> callingConventionComboBox;
|
||||
protected JComboBox<String> 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<String> 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();
|
||||
}
|
||||
}
|
||||
+133
-337
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -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);
|
||||
|
||||
+5
-7
@@ -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);
|
||||
|
||||
+128
-66
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>ProtoOverrideDialog</code> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user