mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Merge remote-tracking branch
'origin/GP-4728-dragonmacher-edit-structure-field--SQUASHED' (Closes #5717)
This commit is contained in:
commit
c95c7581d7
8 changed files with 152 additions and 34 deletions
|
@ -54,6 +54,11 @@ public class DefaultDataTypeManagerService extends DefaultDataTypeArchiveService
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void edit(Structure structure, String fieldName) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataType getDataType(String filterText) {
|
public DataType getDataType(String filterText) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
|
|
|
@ -20,8 +20,7 @@ import java.awt.datatransfer.DataFlavor;
|
||||||
import java.awt.dnd.*;
|
import java.awt.dnd.*;
|
||||||
import java.awt.event.*;
|
import java.awt.event.*;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.EventObject;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
@ -218,6 +217,47 @@ public abstract class CompositeEditorPanel extends JPanel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select the field by the given name in this panel's table.
|
||||||
|
*
|
||||||
|
* @param fieldName the field name
|
||||||
|
*/
|
||||||
|
public void selectField(String fieldName) {
|
||||||
|
|
||||||
|
if (!model.isLoaded()) {
|
||||||
|
return; // disposed; not sure if this can happen
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the given field by name in the current editor, which, if edited, may not match the
|
||||||
|
// original data type. If the user has renamed the field, but not saved the editor, then
|
||||||
|
// we may not find the field.
|
||||||
|
int row = findRowForFieldName(fieldName);
|
||||||
|
if (row == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.getSelectionModel().setSelectionInterval(row, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int findRowForFieldName(String fieldName) {
|
||||||
|
int n = model.getRowCount();
|
||||||
|
for (int row = 0; row < n; row++) {
|
||||||
|
|
||||||
|
DataTypeComponent dtc = model.getComponent(row);
|
||||||
|
if (dtc != null) {
|
||||||
|
String dtcFieldName = dtc.getFieldName();
|
||||||
|
if (Objects.equals(fieldName, dtcFieldName)) {
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
String defaultName = dtc.getDefaultFieldName();
|
||||||
|
if (Objects.equals(fieldName, defaultName)) {
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
protected void cancelCellEditing() {
|
protected void cancelCellEditing() {
|
||||||
TableCellEditor cellEditor = table.getCellEditor();
|
TableCellEditor cellEditor = table.getCellEditor();
|
||||||
if (cellEditor != null) {
|
if (cellEditor != null) {
|
||||||
|
@ -1416,5 +1456,4 @@ public abstract class CompositeEditorPanel extends JPanel
|
||||||
KeyBindingUtils.clearKeyBinding(this, keyStroke);
|
KeyBindingUtils.clearKeyBinding(this, keyStroke);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,4 +89,10 @@ public class StructureEditorProvider extends CompositeEditorProvider {
|
||||||
public String getHelpTopic() {
|
public String getHelpTopic() {
|
||||||
return "DataTypeEditors";
|
return "DataTypeEditors";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void selectField(String fieldName) {
|
||||||
|
if (fieldName != null) {
|
||||||
|
editorPanel.selectField(fieldName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -492,20 +492,14 @@ public class DataTypeManagerPlugin extends ProgramPlugin
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void edit(DataType dt) {
|
public void edit(DataType dt) {
|
||||||
DataTypeManager dataTypeManager = dt.getDataTypeManager();
|
|
||||||
if (dataTypeManager == null) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"DataType " + dt.getPathName() + " has no DataTypeManager! Make sure the " +
|
|
||||||
"given DataType has been resolved by a DataTypeManager");
|
|
||||||
}
|
|
||||||
CategoryPath categoryPath = dt.getCategoryPath();
|
|
||||||
if (categoryPath == null) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"DataType " + dt.getName() + " has no category path!");
|
|
||||||
}
|
|
||||||
editorManager.edit(dt);
|
editorManager.edit(dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void edit(Structure dt, String fieldName) {
|
||||||
|
editorManager.edit(dt, fieldName);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataTypeManager getBuiltInDataTypesManager() {
|
public DataTypeManager getBuiltInDataTypesManager() {
|
||||||
return dataTypeManagerHandler.getBuiltInDataTypesManager();
|
return dataTypeManagerHandler.getBuiltInDataTypesManager();
|
||||||
|
|
|
@ -97,17 +97,8 @@ public class DataTypeEditorManager implements EditorListener {
|
||||||
*/
|
*/
|
||||||
public void edit(DataType dataType) {
|
public void edit(DataType dataType) {
|
||||||
|
|
||||||
DataTypeManager dataTypeManager = dataType.getDataTypeManager();
|
EditorProvider editor = reuseExistingEditor(dataType);
|
||||||
if (dataTypeManager == null) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Datatype " + dataType.getName() + " doesn't have a data type manager specified.");
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorProvider editor = getEditor(dataType);
|
|
||||||
if (editor != null) {
|
if (editor != null) {
|
||||||
ComponentProvider componentProvider = editor.getComponentProvider();
|
|
||||||
plugin.getTool().showComponentProvider(componentProvider, true);
|
|
||||||
componentProvider.toFront();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,13 +115,58 @@ public class DataTypeEditorManager implements EditorListener {
|
||||||
else if (dataType instanceof FunctionDefinition) {
|
else if (dataType instanceof FunctionDefinition) {
|
||||||
editFunctionSignature((FunctionDefinition) dataType);
|
editFunctionSignature((FunctionDefinition) dataType);
|
||||||
}
|
}
|
||||||
if (editor == null) {
|
|
||||||
|
if (editor != null) {
|
||||||
|
editor.addEditorListener(this);
|
||||||
|
editorList.add(editor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a data type editor for editing the given Structure. If the structure is is already
|
||||||
|
* being edited then it is brought to the front. Otherwise, a new editor is created and
|
||||||
|
* displayed.
|
||||||
|
* @param structure the structure.
|
||||||
|
* @param fieldName the optional name of the field to select in the editor.
|
||||||
|
*/
|
||||||
|
public void edit(Structure structure, String fieldName) {
|
||||||
|
|
||||||
|
StructureEditorProvider editor = (StructureEditorProvider) getEditor(structure);
|
||||||
|
if (editor != null) {
|
||||||
|
reuseExistingEditor(structure);
|
||||||
|
editor.selectField(fieldName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
editor = new StructureEditorProvider(plugin, structure,
|
||||||
|
showStructureNumbersInHex());
|
||||||
|
editor.selectField(fieldName);
|
||||||
editor.addEditorListener(this);
|
editor.addEditorListener(this);
|
||||||
editorList.add(editor);
|
editorList.add(editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private EditorProvider reuseExistingEditor(DataType dataType) {
|
||||||
|
DataTypeManager dataTypeManager = dataType.getDataTypeManager();
|
||||||
|
if (dataTypeManager == null) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Datatype " + dataType.getName() + " doesn't have a data type manager specified.");
|
||||||
|
}
|
||||||
|
|
||||||
|
CategoryPath categoryPath = dataType.getCategoryPath();
|
||||||
|
if (categoryPath == null) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"DataType " + dataType.getName() + " has no category path!");
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorProvider editor = getEditor(dataType);
|
||||||
|
if (editor != null) {
|
||||||
|
ComponentProvider componentProvider = editor.getComponentProvider();
|
||||||
|
plugin.getTool().showComponentProvider(componentProvider, true);
|
||||||
|
componentProvider.toFront();
|
||||||
|
}
|
||||||
|
return editor;
|
||||||
|
}
|
||||||
|
|
||||||
private void installEditorActions() {
|
private void installEditorActions() {
|
||||||
|
|
||||||
// composite editor actions
|
// composite editor actions
|
||||||
|
|
|
@ -22,8 +22,7 @@ import javax.swing.tree.TreePath;
|
||||||
|
|
||||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||||
import ghidra.framework.plugintool.ServiceInfo;
|
import ghidra.framework.plugintool.ServiceInfo;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.data.DataTypeManagerChangeListener;
|
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -88,14 +87,24 @@ public interface DataTypeManagerService extends DataTypeQueryService, DataTypeAr
|
||||||
public boolean isEditable(DataType dt);
|
public boolean isEditable(DataType dt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pop up an editor dialog for the given data type.
|
* Pop up an editor window for the given data type.
|
||||||
*
|
*
|
||||||
* @param dt data type that either a Structure or a Union; built in types cannot be edited
|
* @param dt the data type; built in types cannot be edited
|
||||||
* @throws IllegalArgumentException if the given has not been resolved by a DataTypeManager;
|
* @throws IllegalArgumentException if the given has not been resolved by a DataTypeManager;
|
||||||
* in other words, if {@link DataType#getDataTypeManager()} returns null.
|
* in other words, if {@link DataType#getDataTypeManager()} returns null
|
||||||
*/
|
*/
|
||||||
public void edit(DataType dt);
|
public void edit(DataType dt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pop up an editor window for the given structure.
|
||||||
|
*
|
||||||
|
* @param structure the structure
|
||||||
|
* @param fieldName the optional structure field name to select in the editor window
|
||||||
|
* @throws IllegalArgumentException if the given has not been resolved by a DataTypeManager;
|
||||||
|
* in other words, if {@link DataType#getDataTypeManager()} returns null
|
||||||
|
*/
|
||||||
|
public void edit(Structure structure, String fieldName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects the given data type in the display of data types. A null <code>dataType</code>
|
* Selects the given data type in the display of data types. A null <code>dataType</code>
|
||||||
* value will clear the current selection.
|
* value will clear the current selection.
|
||||||
|
|
|
@ -99,6 +99,11 @@ public class TestDoubleDataTypeManagerService implements DataTypeManagerService
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void edit(Structure structure, String fieldName) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void closeArchive(DataTypeManager dtm) {
|
public void closeArchive(DataTypeManager dtm) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
|
|
|
@ -17,14 +17,16 @@ package ghidra.app.plugin.core.decompile.actions;
|
||||||
|
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
import docking.action.MenuData;
|
import docking.action.MenuData;
|
||||||
|
import ghidra.app.decompiler.ClangFieldToken;
|
||||||
|
import ghidra.app.decompiler.ClangToken;
|
||||||
|
import ghidra.app.decompiler.component.DecompilerPanel;
|
||||||
import ghidra.app.decompiler.component.DecompilerUtils;
|
import ghidra.app.decompiler.component.DecompilerUtils;
|
||||||
import ghidra.app.plugin.core.datamgr.util.DataTypeUtils;
|
import ghidra.app.plugin.core.datamgr.util.DataTypeUtils;
|
||||||
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
||||||
import ghidra.app.services.DataTypeManagerService;
|
import ghidra.app.services.DataTypeManagerService;
|
||||||
import ghidra.app.util.HelpTopics;
|
import ghidra.app.util.HelpTopics;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.data.DataTypeManager;
|
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.Function;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
import ghidra.util.UndefinedFunction;
|
import ghidra.util.UndefinedFunction;
|
||||||
|
@ -74,9 +76,31 @@ public class EditDataTypeAction extends AbstractDecompilerAction {
|
||||||
if (baseDtDTM != dataTypeManager) {
|
if (baseDtDTM != dataTypeManager) {
|
||||||
baseDataType = baseDataType.clone(dataTypeManager);
|
baseDataType = baseDataType.clone(dataTypeManager);
|
||||||
}
|
}
|
||||||
final DataTypeManagerService service =
|
|
||||||
|
DataTypeManagerService service =
|
||||||
context.getTool().getService(DataTypeManagerService.class);
|
context.getTool().getService(DataTypeManagerService.class);
|
||||||
service.edit(baseDataType);
|
|
||||||
|
if (dataType instanceof Structure structure) {
|
||||||
|
editStructure(service, structure, context);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
service.edit(baseDataType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void editStructure(DataTypeManagerService service, Structure structure,
|
||||||
|
DecompilerActionContext context) {
|
||||||
|
|
||||||
|
DecompilerPanel decompilerPanel = context.getDecompilerPanel();
|
||||||
|
ClangToken tokenAtCursor = decompilerPanel.getTokenAtCursor();
|
||||||
|
if (tokenAtCursor instanceof ClangFieldToken) {
|
||||||
|
String fieldName = tokenAtCursor.getText();
|
||||||
|
if (fieldName != null) {
|
||||||
|
service.edit(structure, fieldName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
service.edit(structure);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue