GP-3755 - Added filter to the Memory Map provider

This commit is contained in:
dragonmacher 2023-08-22 18:34:10 -04:00
parent b261137b40
commit 6afed33ce0
7 changed files with 276 additions and 281 deletions

View file

@ -15,30 +15,33 @@
*/ */
package ghidra.app.plugin.core.memory; package ghidra.app.plugin.core.memory;
import java.awt.Cursor;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.swing.JTable; import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellEditor;
import org.apache.commons.lang3.exception.ExceptionUtils;
import docking.widgets.OptionDialog; import docking.widgets.OptionDialog;
import docking.widgets.dialogs.NumberInputDialog; import docking.widgets.dialogs.NumberInputDialog;
import docking.widgets.table.AbstractSortedTableModel; import docking.widgets.table.AbstractSortedTableModel;
/**
* Table Model for a Table where each entry represents a MemoryBlock
* from a Program's Memory.
*/
import ghidra.framework.model.DomainFile; import ghidra.framework.model.DomainFile;
import ghidra.framework.store.LockException; import ghidra.framework.store.LockException;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.*; import ghidra.program.model.mem.*;
import ghidra.program.util.ProgramLocation;
import ghidra.program.util.ProgramSelection;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.Swing;
import ghidra.util.table.ProgramTableModel;
class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> { /**
* Table Model for a Table where each entry represents a MemoryBlock from a Program's Memory.
*/
class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> implements ProgramTableModel {
final static byte NAME = 0; final static byte NAME = 0;
final static byte START = 1; final static byte START = 1;
@ -70,9 +73,11 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
final static String SOURCE_COL = "Source"; final static String SOURCE_COL = "Source";
final static String COMMENT_COL = "Comment"; final static String COMMENT_COL = "Comment";
private Program program; private final static Cursor WAIT_CURSOR = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR);
private final static Cursor DEFAULT_CURSOR = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
private ArrayList<MemoryBlock> memList; private Program program;
private List<MemoryBlock> memList;
private MemoryMapProvider provider; private MemoryMapProvider provider;
private final static String COLUMN_NAMES[] = private final static String COLUMN_NAMES[] =
@ -81,9 +86,12 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
MemoryMapModel(MemoryMapProvider provider, Program program) { MemoryMapModel(MemoryMapProvider provider, Program program) {
super(START); super(START);
this.program = program;
this.provider = provider; this.provider = provider;
setProgram(program);
}
void setProgram(Program program) {
this.program = program;
populateMap(); populateMap();
} }
@ -91,6 +99,7 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
memList = new ArrayList<>(); memList = new ArrayList<>();
if (program == null) { if (program == null) {
fireTableDataChanged();
return; return;
} }
@ -141,12 +150,6 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
return COLUMN_NAMES[column]; return COLUMN_NAMES[column];
} }
/**
* Convenience method for locating columns by name.
* Implementation is naive so this should be overridden if
* this method is to be called often. This method is not
* in the TableModel interface and is not used by the JTable.
*/
@Override @Override
public int findColumn(String columnName) { public int findColumn(String columnName) {
for (int i = 0; i < COLUMN_NAMES.length; i++) { for (int i = 0; i < COLUMN_NAMES.length; i++) {
@ -157,9 +160,6 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
return 0; return 0;
} }
/**
* Returns Object.class by default
*/
@Override @Override
public Class<?> getColumnClass(int columnIndex) { public Class<?> getColumnClass(int columnIndex) {
if (columnIndex == READ || columnIndex == WRITE || columnIndex == EXECUTE || if (columnIndex == READ || columnIndex == WRITE || columnIndex == EXECUTE ||
@ -169,9 +169,6 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
return String.class; return String.class;
} }
/**
* Return whether this column is editable.
*/
@Override @Override
public boolean isCellEditable(int rowIndex, int columnIndex) { public boolean isCellEditable(int rowIndex, int columnIndex) {
@ -195,15 +192,6 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
} }
} }
/**
* Returns the number of records managed by the data source object. A
* <B>JTable</B> uses this method to determine how many rows it
* should create and display. This method should be quick, as it
* is call by <B>JTable</B> quite frequently.
*
* @return the number or rows in the model
* @see #getColumnCount
*/
@Override @Override
public int getRowCount() { public int getRowCount() {
return memList.size(); return memList.size();
@ -226,157 +214,134 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
if (rowIndex < 0 || rowIndex >= memList.size()) { if (rowIndex < 0 || rowIndex >= memList.size()) {
return null; return null;
} }
MemoryBlock block = memList.get(rowIndex);
try {
// make sure block is still valid
block.getStart();
}
catch (ConcurrentModificationException e) {
update();
}
return memList.get(rowIndex); return memList.get(rowIndex);
} }
/**
* This empty implementation is provided so users don't have to implement
* this method if their data model is not editable.
*/
@Override @Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) { public void setValueAt(Object aValue, int row, int column) {
provider.setCursor(MemoryMapPlugin.WAIT_CURSOR); provider.setCursor(WAIT_CURSOR);
try { try {
MemoryBlock block = getBlockAt(rowIndex); MemoryBlock block = getBlockAt(row);
if (block == null) { if (block == null) {
// this can happen when the tool is closing while an edit is open // this can happen when the tool is closing while an edit is open
return; return;
} }
switch (columnIndex) { doSetValueAt(aValue, row, column, block);
case NAME:
String name = ((String) aValue).trim();
if (!verifyRenameAllowed(block, name)) {
return;
}
if (name.length() == 0) {
Msg.showError(this, provider.getComponent(), "Enter Block Label",
"Please enter a label name.");
break;
}
if (name.equals(block.getName())) {
break;
}
if (!Memory.isValidMemoryBlockName(name)) {
Msg.showError(this, provider.getComponent(), "Invalid Name",
"Invalid Memory Block Name: " + name);
break;
}
if (!name.equals(block.getName())) {
program.withTransaction("Rename Memory Block", () -> {
try {
block.setName(name);
}
catch (LockException e) {
provider.setStatusText(e.getMessage());
}
});
}
break;
case READ: {
program.withTransaction("Set Read State", () -> {
boolean value = ((Boolean) aValue).booleanValue();
block.setRead(value);
provider.setStatusText("");
});
break;
}
case WRITE: {
program.withTransaction("Set Write State", () -> {
boolean value = ((Boolean) aValue).booleanValue();
block.setWrite(value);
provider.setStatusText("");
});
break;
}
case EXECUTE: {
int id = program.startTransaction("Set Execute State");
try {
boolean value = ((Boolean) aValue).booleanValue();
block.setExecute(value);
provider.setStatusText("");
program.endTransaction(id, true);
}
catch (RuntimeException e) {
program.endTransaction(id, false);
throw e;
}
break;
}
case VOLATILE: {
int id = program.startTransaction("Set Volatile State");
try {
boolean value = ((Boolean) aValue).booleanValue();
block.setVolatile(value);
provider.setStatusText("");
program.endTransaction(id, true);
}
catch (RuntimeException e) {
program.endTransaction(id, false);
throw e;
}
break;
}
case INIT:
MemoryBlockType blockType = block.getType();
if (blockType == MemoryBlockType.BIT_MAPPED ||
blockType == MemoryBlockType.BYTE_MAPPED) {
showMessage("Cannot change intialized memory state of a mapped Block");
return;
}
provider.setStatusText("");
boolean booleanValue = ((Boolean) aValue).booleanValue();
if (booleanValue) {
initializeBlock(block);
}
else {
revertBlockToUninitialized(block);
}
return;
case SOURCE:
break;
case COMMENT:
String cmt = block.getComment();
if (cmt == null || !cmt.equals(aValue)) {
String value = (String) aValue;
if (value.length() == 0) {
value = null;
}
int id = program.startTransaction("Set Comment State");
try {
block.setComment(value);
program.endTransaction(id, true);
}
catch (RuntimeException e) {
program.endTransaction(id, false);
throw e;
}
}
break;
default:
break;
}
fireTableRowsUpdated(rowIndex, rowIndex);
} }
finally { finally {
provider.setCursor(MemoryMapPlugin.NORM_CURSOR); provider.setCursor(DEFAULT_CURSOR);
}
}
private void doSetValueAt(Object aValue, int row, int column, MemoryBlock block) {
switch (column) {
case NAME:
setName(block, (String) aValue);
break;
case READ: {
program.withTransaction("Set Read State", () -> {
boolean value = ((Boolean) aValue).booleanValue();
block.setRead(value);
provider.setStatusText("");
});
break;
}
case WRITE: {
program.withTransaction("Set Write State", () -> {
boolean value = ((Boolean) aValue).booleanValue();
block.setWrite(value);
provider.setStatusText("");
});
break;
}
case EXECUTE: {
program.withTransaction("Set Execute State", () -> {
boolean value = ((Boolean) aValue).booleanValue();
block.setExecute(value);
provider.setStatusText("");
});
break;
}
case VOLATILE: {
program.withTransaction("Set Volatile State", () -> {
boolean value = ((Boolean) aValue).booleanValue();
block.setVolatile(value);
provider.setStatusText("");
});
break;
}
case INIT:
MemoryBlockType blockType = block.getType();
if (blockType == MemoryBlockType.BIT_MAPPED ||
blockType == MemoryBlockType.BYTE_MAPPED) {
showMessage("Cannot change intialized memory state of a mapped Block");
break;
}
provider.setStatusText("");
boolean booleanValue = ((Boolean) aValue).booleanValue();
if (booleanValue) {
initializeBlock(block);
}
else {
revertBlockToUninitialized(block);
}
break;
case SOURCE:
break;
case COMMENT:
setComment(block, (String) aValue);
break;
default:
break;
}
fireTableRowsUpdated(row, column);
}
private void setComment(MemoryBlock block, String aValue) {
String cmt = block.getComment();
if (cmt == null || !cmt.equals(aValue)) {
if (aValue.length() == 0) {
aValue = null;
}
String newValue = aValue;
program.withTransaction("Set Comment", () -> {
block.setComment(newValue);
});
}
}
private void setName(MemoryBlock block, String name) {
name = name.trim();
if (!verifyRenameAllowed(block, name)) {
return;
}
if (name.length() == 0) {
Msg.showError(this, provider.getComponent(), "Enter Block Label",
"Please enter a label name.");
return;
}
if (name.equals(block.getName())) {
return;
}
if (!Memory.isValidMemoryBlockName(name)) {
Msg.showError(this, provider.getComponent(), "Invalid Name",
"Invalid Memory Block Name: " + name);
return;
}
try {
String newName = name;
program.withTransaction("Rename Memory Block", () -> {
block.setName(newName);
});
}
catch (LockException e) {
this.provider.setStatusText(e.getMessage());
} }
} }
@ -438,15 +403,14 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
} }
catch (Throwable t) { catch (Throwable t) {
program.endTransaction(id, false); program.endTransaction(id, false);
String msg = t.getMessage(); String msg = ExceptionUtils.getMessage(t);
msg = msg == null ? t.toString() : msg;
Msg.showError(this, provider.getComponent(), "Block Initialization Failed", msg, t); Msg.showError(this, provider.getComponent(), "Block Initialization Failed", msg, t);
} }
} }
private void showMessage(final String msg) { private void showMessage(String msg) {
// mouse listeners wipe out the message so show it later... // mouse listeners wipe out the message so show it later...
SwingUtilities.invokeLater(() -> provider.setStatusText(msg)); Swing.runLater(() -> provider.setStatusText(msg));
} }
@Override @Override
@ -530,6 +494,44 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
return new MemoryMapComparator(columnIndex); return new MemoryMapComparator(columnIndex);
} }
@Override
public ProgramLocation getProgramLocation(int row, int column) {
MemoryBlock block = getRowObject(row);
Address address = block.getStart();
if (column == END) {
address = block.getEnd();
}
return new ProgramLocation(program, address);
}
@Override
public ProgramSelection getProgramSelection(int[] rows) {
if (rows.length == 0) {
return null;
}
AddressSet addressSet = new AddressSet();
for (int row : rows) {
MemoryBlock block = getRowObject(row);
Address start = block.getStart();
Address end = block.getEnd();
if (start.isMemoryAddress() && end.isMemoryAddress()) {
addressSet.addRange(start, end);
}
}
return new ProgramSelection(addressSet);
}
@Override
public Program getProgram() {
return program;
}
private class MemoryMapComparator implements Comparator<MemoryBlock> { private class MemoryMapComparator implements Comparator<MemoryBlock> {
private final int sortColumn; private final int sortColumn;
@ -607,4 +609,5 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
} }
} }
} }
} }

View file

@ -15,8 +15,6 @@
*/ */
package ghidra.app.plugin.core.memory; package ghidra.app.plugin.core.memory;
import java.awt.Cursor;
import ghidra.app.CorePluginPackage; import ghidra.app.CorePluginPackage;
import ghidra.app.events.ProgramLocationPluginEvent; import ghidra.app.events.ProgramLocationPluginEvent;
import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.plugin.PluginCategoryNames;
@ -51,9 +49,6 @@ import ghidra.program.util.ProgramLocation;
//@formatter:on //@formatter:on
public class MemoryMapPlugin extends ProgramPlugin implements DomainObjectListener { public class MemoryMapPlugin extends ProgramPlugin implements DomainObjectListener {
final static Cursor WAIT_CURSOR = new Cursor(Cursor.WAIT_CURSOR);
final static Cursor NORM_CURSOR = new Cursor(Cursor.DEFAULT_CURSOR);
private MemoryMapProvider provider; private MemoryMapProvider provider;
private GoToService goToService; private GoToService goToService;
private MemoryMapManager memManager; private MemoryMapManager memManager;

View file

@ -26,7 +26,6 @@ import javax.swing.table.TableModel;
import docking.ActionContext; import docking.ActionContext;
import docking.action.DockingAction; import docking.action.DockingAction;
import docking.action.ToolBarData; import docking.action.ToolBarData;
import docking.widgets.label.GLabel;
import docking.widgets.table.*; import docking.widgets.table.*;
import docking.widgets.textfield.GValidatedTextField.MaxLengthField; import docking.widgets.textfield.GValidatedTextField.MaxLengthField;
import generic.theme.GIcon; import generic.theme.GIcon;
@ -41,18 +40,19 @@ import ghidra.program.model.mem.MemoryBlockType;
import ghidra.util.HelpLocation; import ghidra.util.HelpLocation;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.table.GhidraTable; import ghidra.util.table.GhidraTable;
import ghidra.util.table.GhidraTableFilterPanel;
import ghidra.util.table.actions.MakeProgramSelectionAction;
/** /**
* Provider for the memory map Component. * Provider for the memory map Component.
*
*/ */
class MemoryMapProvider extends ComponentProviderAdapter { class MemoryMapProvider extends ComponentProviderAdapter {
private final static int MAX_SIZE = 256; private final static int MAX_SIZE = 256;
private JPanel mainPanel; private JPanel mainPanel;
private GTable memTable; private MemoryMapModel tableModel;
private JScrollPane memPane; private GhidraTable table;
private MemoryMapModel mapModel; private GTableFilterPanel<MemoryBlock> filterPanel;
private DockingAction addAction; private DockingAction addAction;
private DockingAction moveAction; private DockingAction moveAction;
@ -84,6 +84,7 @@ class MemoryMapProvider extends ComponentProviderAdapter {
@Override @Override
public void componentShown() { public void componentShown() {
updateMap(); updateMap();
contextChanged();
} }
@Override @Override
@ -96,7 +97,7 @@ class MemoryMapProvider extends ComponentProviderAdapter {
if (program == null) { if (program == null) {
return null; return null;
} }
return new ProgramActionContext(this, program); return new ProgramActionContext(this, program, table);
} }
void setStatusText(String msg) { void setStatusText(String msg) {
@ -105,7 +106,7 @@ class MemoryMapProvider extends ComponentProviderAdapter {
void dispose() { void dispose() {
removeFromTool(); removeFromTool();
memTable.dispose(); filterPanel.dispose();
plugin = null; plugin = null;
program = null; program = null;
tool = null; tool = null;
@ -113,7 +114,7 @@ class MemoryMapProvider extends ComponentProviderAdapter {
void setProgram(Program program) { void setProgram(Program program) {
this.program = program; this.program = program;
updateMap(program); updateProgram(program);
arrangeTable(); arrangeTable();
} }
@ -121,69 +122,67 @@ class MemoryMapProvider extends ComponentProviderAdapter {
return memManager; return memManager;
} }
/**
* Creates the Main Panel for the Memory Map Dialog
*/
private JPanel buildMainPanel() { private JPanel buildMainPanel() {
JPanel memPanel = new JPanel(new BorderLayout()); JPanel memPanel = new JPanel(new BorderLayout());
mapModel = new MemoryMapModel(this, null); tableModel = new MemoryMapModel(this, null);
memTable = new MemoryMapTable(mapModel); table = new MemoryMapTable(tableModel);
filterPanel = new GhidraTableFilterPanel<>(table, tableModel);
memTable.setAutoCreateColumnsFromModel(false); table.setAutoCreateColumnsFromModel(false);
GTableCellRenderer monoRenderer = new GTableCellRenderer(); GTableCellRenderer monoRenderer = new GTableCellRenderer();
monoRenderer.setFont(monoRenderer.getFixedWidthFont()); monoRenderer.setFont(monoRenderer.getFixedWidthFont());
TableColumn column = memTable.getColumn(MemoryMapModel.START_COL); TableColumn column = table.getColumn(MemoryMapModel.START_COL);
column.setCellRenderer(monoRenderer); column.setCellRenderer(monoRenderer);
column = memTable.getColumn(MemoryMapModel.END_COL); column = table.getColumn(MemoryMapModel.END_COL);
column.setCellRenderer(monoRenderer); column.setCellRenderer(monoRenderer);
column = memTable.getColumn(MemoryMapModel.LENGTH_COL); column = table.getColumn(MemoryMapModel.LENGTH_COL);
column.setCellRenderer(monoRenderer); column.setCellRenderer(monoRenderer);
column = memTable.getColumn(MemoryMapModel.READ_COL); column = table.getColumn(MemoryMapModel.READ_COL);
column.setCellRenderer(new GBooleanCellRenderer()); column.setCellRenderer(new GBooleanCellRenderer());
column = memTable.getColumn(MemoryMapModel.WRITE_COL); column = table.getColumn(MemoryMapModel.WRITE_COL);
column.setCellRenderer(new GBooleanCellRenderer()); column.setCellRenderer(new GBooleanCellRenderer());
column = memTable.getColumn(MemoryMapModel.EXECUTE_COL); column = table.getColumn(MemoryMapModel.EXECUTE_COL);
column.setCellRenderer(new GBooleanCellRenderer()); column.setCellRenderer(new GBooleanCellRenderer());
column = memTable.getColumn(MemoryMapModel.VOLATILE_COL); column = table.getColumn(MemoryMapModel.VOLATILE_COL);
column.setCellRenderer(new GBooleanCellRenderer()); column.setCellRenderer(new GBooleanCellRenderer());
column = memTable.getColumn(MemoryMapModel.OVERLAY_COL); column = table.getColumn(MemoryMapModel.OVERLAY_COL);
column.setCellRenderer(new GBooleanCellRenderer()); column.setCellRenderer(new GBooleanCellRenderer());
column = memTable.getColumn(MemoryMapModel.INIT_COL); column = table.getColumn(MemoryMapModel.INIT_COL);
column.setCellRenderer(new GBooleanCellRenderer()); column.setCellRenderer(new GBooleanCellRenderer());
memTable.setDefaultEditor(String.class, table.setDefaultEditor(String.class,
new GTableTextCellEditor(new MaxLengthField(MAX_SIZE))); new GTableTextCellEditor(new MaxLengthField(MAX_SIZE)));
memPane = new JScrollPane(memTable); table.setPreferredScrollableViewportSize(new Dimension(700, 105));
memTable.setPreferredScrollableViewportSize(new Dimension(700, 105));
memTable.addMouseListener(new MouseHandler()); table.addMouseListener(new MouseHandler());
memTable.addKeyListener(new KeyHandler()); table.addKeyListener(new KeyHandler());
memTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
ListSelectionModel lsm = memTable.getSelectionModel(); ListSelectionModel lsm = table.getSelectionModel();
lsm.addListSelectionListener(e -> { lsm.addListSelectionListener(e -> {
// Ignore extra messages.
if (e.getValueIsAdjusting()) { if (e.getValueIsAdjusting()) {
return; return;
} }
ListSelectionModel model = (ListSelectionModel) e.getSource(); ListSelectionModel model = (ListSelectionModel) e.getSource();
enableOptions(model); enableOptions(model);
contextChanged();
}); });
memPanel.add(new GLabel("Memory Blocks", SwingConstants.CENTER), BorderLayout.NORTH); memPanel.add(new JScrollPane(table), BorderLayout.CENTER);
memPanel.add(memPane, BorderLayout.CENTER); memPanel.add(filterPanel, BorderLayout.SOUTH);
return memPanel; return memPanel;
} }
private void addLocalActions() { private void addLocalActions() {
Icon addImage = new GIcon("icon.plugin.memorymap.add"); Icon addImage = new GIcon("icon.plugin.memorymap.add");
addAction = new MemoryMapAction("Add Block", addImage) { addAction = new MemoryMapAction("Add Block", addImage) {
@ -294,6 +293,11 @@ class MemoryMapProvider extends ComponentProviderAdapter {
setBaseAction.setDescription("Set Image Base"); setBaseAction.setDescription("Set Image Base");
tool.addLocalAction(this, setBaseAction); tool.addLocalAction(this, setBaseAction);
MakeProgramSelectionAction action =
new MakeProgramSelectionAction(plugin, table);
action.getToolBarData().setToolBarGroup("B"); // the other actions are in group 'A'
tool.addLocalAction(this, action);
} }
private void setBase() { private void setBase() {
@ -332,12 +336,6 @@ class MemoryMapProvider extends ComponentProviderAdapter {
} }
} }
/**
* Enable/disable the expand up/down actions according to the selected
* block.
*
* @param numSelected number of blocks selected
*/
private void enableExpandActions(int numSelected) { private void enableExpandActions(int numSelected) {
if (numSelected != 1) { if (numSelected != 1) {
expandUpAction.setEnabled(false); expandUpAction.setEnabled(false);
@ -368,7 +366,11 @@ class MemoryMapProvider extends ComponentProviderAdapter {
} }
JTable getTable() { JTable getTable() {
return memTable; return table;
}
MemoryMapModel getModel() {
return tableModel;
} }
/** /**
@ -376,7 +378,7 @@ class MemoryMapProvider extends ComponentProviderAdapter {
*/ */
void updateMap() { void updateMap() {
if (isVisible()) { if (isVisible()) {
mapModel.update(); tableModel.update();
arrangeTable(); arrangeTable();
updateTitle(); updateTitle();
} }
@ -385,7 +387,7 @@ class MemoryMapProvider extends ComponentProviderAdapter {
void updateData() { void updateData() {
if (isVisible()) { if (isVisible()) {
updateTitle(); updateTitle();
memTable.repaint(); table.repaint();
} }
} }
@ -398,9 +400,9 @@ class MemoryMapProvider extends ComponentProviderAdapter {
/** /**
* Update the memory map with the new program's memory * Update the memory map with the new program's memory
*/ */
private void updateMap(Program updateProgram) { private void updateProgram(Program updatedProgram) {
enableOptions(null); enableOptions(null);
if (updateProgram == null) { if (updatedProgram == null) {
addAction.setEnabled(false); addAction.setEnabled(false);
setBaseAction.setEnabled(false); setBaseAction.setEnabled(false);
} }
@ -408,8 +410,7 @@ class MemoryMapProvider extends ComponentProviderAdapter {
setBaseAction.setEnabled(true); setBaseAction.setEnabled(true);
} }
mapModel = new MemoryMapModel(this, updateProgram); tableModel.setProgram(updatedProgram);
memTable.setModel(mapModel);
updateTitle(); updateTitle();
} }
@ -420,48 +421,48 @@ class MemoryMapProvider extends ComponentProviderAdapter {
// memTable.setRowHeight(20); // memTable.setRowHeight(20);
TableColumn column; TableColumn column;
column = memTable.getColumn(MemoryMapModel.READ_COL); column = table.getColumn(MemoryMapModel.READ_COL);
if (column != null) { if (column != null) {
column.setMaxWidth(25); column.setMaxWidth(25);
column.setMinWidth(25); column.setMinWidth(25);
column.setResizable(false); column.setResizable(false);
} }
column = memTable.getColumn(MemoryMapModel.WRITE_COL); column = table.getColumn(MemoryMapModel.WRITE_COL);
if (column != null) { if (column != null) {
column.setMaxWidth(25); column.setMaxWidth(25);
column.setMinWidth(25); column.setMinWidth(25);
column.setResizable(false); column.setResizable(false);
} }
column = memTable.getColumn(MemoryMapModel.EXECUTE_COL); column = table.getColumn(MemoryMapModel.EXECUTE_COL);
if (column != null) { if (column != null) {
column.setMaxWidth(25); column.setMaxWidth(25);
column.setMinWidth(25); column.setMinWidth(25);
column.setResizable(false); column.setResizable(false);
} }
column = memTable.getColumn(MemoryMapModel.VOLATILE_COL); column = table.getColumn(MemoryMapModel.VOLATILE_COL);
if (column != null) { if (column != null) {
column.setMaxWidth(65); column.setMaxWidth(65);
column.setMinWidth(65); column.setMinWidth(65);
column.setResizable(false); column.setResizable(false);
} }
column = memTable.getColumn(MemoryMapModel.OVERLAY_COL); column = table.getColumn(MemoryMapModel.OVERLAY_COL);
if (column != null) { if (column != null) {
column.setMaxWidth(65); column.setMaxWidth(65);
column.setMinWidth(65); column.setMinWidth(65);
column.setResizable(false); column.setResizable(false);
} }
column = memTable.getColumn(MemoryMapModel.BLOCK_TYPE_COL); column = table.getColumn(MemoryMapModel.BLOCK_TYPE_COL);
if (column != null) { if (column != null) {
column.setMinWidth(60); column.setMinWidth(60);
// column.setResizable(true); // column.setResizable(true);
} }
column = memTable.getColumn(MemoryMapModel.INIT_COL); column = table.getColumn(MemoryMapModel.INIT_COL);
if (column != null) { if (column != null) {
column.setMaxWidth(80); column.setMaxWidth(80);
column.setMinWidth(80); column.setMinWidth(80);
@ -484,7 +485,7 @@ class MemoryMapProvider extends ComponentProviderAdapter {
if (!e.isPopupTrigger()) { if (!e.isPopupTrigger()) {
if ((e.getModifiersEx() & if ((e.getModifiersEx() &
(InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK)) == 0) { (InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK)) == 0) {
selectAddress(); navigateToAddress();
} }
} }
} }
@ -499,30 +500,30 @@ class MemoryMapProvider extends ComponentProviderAdapter {
@Override @Override
public void keyPressed(KeyEvent e) { public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) { if (e.getKeyCode() == KeyEvent.VK_ENTER) {
selectAddress(); navigateToAddress();
e.consume(); e.consume();
} }
} }
} }
private void selectAddress() { private void navigateToAddress() {
int row = memTable.getSelectedRow(); int viewRow = table.getSelectedRow();
int viewColumn = memTable.getSelectedColumn(); int viewColumn = table.getSelectedColumn();
int col = memTable.convertColumnIndexToModel(viewColumn); int modelColumn = table.convertColumnIndexToModel(viewColumn);
MemoryBlock block = mapModel.getBlockAt(row); MemoryBlock block = tableModel.getBlockAt(viewRow);
if (block != null && (col == 1 || col == 2)) { if (block != null && (modelColumn == 1 || modelColumn == 2)) {
Address addr = (col == 1 ? block.getStart() : block.getEnd()); Address addr = (modelColumn == 1 ? block.getStart() : block.getEnd());
plugin.blockSelected(block, addr); plugin.blockSelected(block, addr);
memTable.setRowSelectionInterval(row, row); table.setRowSelectionInterval(viewRow, viewRow);
} }
} }
private MemoryBlock getSelectedBlock() { private MemoryBlock getSelectedBlock() {
int row = memTable.getSelectedRow(); int row = table.getSelectedRow();
if (row < 0) { if (row < 0) {
return null; return null;
} }
return mapModel.getBlockAt(row); return tableModel.getBlockAt(row);
} }
/** /**
@ -534,12 +535,12 @@ class MemoryMapProvider extends ComponentProviderAdapter {
return; return;
} }
ArrayList<MemoryBlock> delBlocks = new ArrayList<>(); ArrayList<MemoryBlock> delBlocks = new ArrayList<>();
int delRows[] = memTable.getSelectedRows(); int delRows[] = table.getSelectedRows();
for (int element : delRows) { for (int element : delRows) {
MemoryBlock block = mapModel.getBlockAt(element); MemoryBlock block = tableModel.getBlockAt(element);
delBlocks.add(block); delBlocks.add(block);
} }
memTable.clearSelection(); table.clearSelection();
deleteBlock(delBlocks); deleteBlock(delBlocks);
} }
@ -642,12 +643,12 @@ class MemoryMapProvider extends ComponentProviderAdapter {
*/ */
private void mergeBlocks() { private void mergeBlocks() {
ArrayList<MemoryBlock> blocks = new ArrayList<>(); ArrayList<MemoryBlock> blocks = new ArrayList<>();
int rows[] = memTable.getSelectedRows(); int rows[] = table.getSelectedRows();
for (int element : rows) { for (int element : rows) {
MemoryBlock block = mapModel.getBlockAt(element); MemoryBlock block = tableModel.getBlockAt(element);
blocks.add(block); blocks.add(block);
} }
memTable.clearSelection(); table.clearSelection();
memManager.mergeBlocks(blocks); memManager.mergeBlocks(blocks);
} }
@ -670,9 +671,9 @@ class MemoryMapProvider extends ComponentProviderAdapter {
return plugin.getTool(); return plugin.getTool();
} }
// ================================================================================================== //==================================================================================================
// Inner Classes // Inner Classes
// ================================================================================================== //==================================================================================================
private class MemoryMapTable extends GhidraTable { private class MemoryMapTable extends GhidraTable {
MemoryMapTable(TableModel model) { MemoryMapTable(TableModel model) {
@ -691,7 +692,7 @@ class MemoryMapProvider extends ComponentProviderAdapter {
private abstract class MemoryMapAction extends DockingAction { private abstract class MemoryMapAction extends DockingAction {
MemoryMapAction(String name, Icon icon) { MemoryMapAction(String name, Icon icon) {
super(name, plugin.getName()); super(name, plugin.getName());
this.setToolBarData(new ToolBarData(icon, null)); this.setToolBarData(new ToolBarData(icon, "A"));
} }
public boolean checkExclusiveAccess() { public boolean checkExclusiveAccess() {

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,26 +20,23 @@ import ghidra.program.util.ProgramLocation;
import ghidra.program.util.ProgramSelection; import ghidra.program.util.ProgramSelection;
/** /**
* An interface for translating table rows and columns * An interface for translating table rows and columns into program locations and selections.
* into program locations and selections.
*/ */
public interface ProgramTableModel { public interface ProgramTableModel {
/** /**
* Returns a program location corresponding the given row and column. * Returns a program location corresponding the given row and column.
* Motivation: * <p>
* Given a table that has a column that contains addresses. * Motivation: Given a table that has a column that contains addresses. If the user clicks on
* If the user clicks on this column, then it would be nice * this column, then it would be nice to have the CodeBrowser navigate to this address.
* to have the CodeBrowser navigate to this address. * @param row the row
* @param row the row * @param modelColumn the column in the model's index
* @param column the column * @return a program location corresponding the given row and column
* @return a program location corresponding the given row and column */
*/ public ProgramLocation getProgramLocation(int row, int modelColumn);
public ProgramLocation getProgramLocation(int row, int column);
/** /**
* Returns a program selection corresponding to the * Returns a program selection corresponding to the specified row index array. This array will
* specified row index array. This array will contain * contain the currently selected rows.
* the currently selected rows.
* @param rows the currently selected rows. * @param rows the currently selected rows.
* @return a program selection * @return a program selection
*/ */

View file

@ -673,8 +673,7 @@ public class MemoryMapProvider1Test extends AbstractGhidraHeadedIntegrationTest
waitForSwing(); waitForSwing();
provider = plugin.getMemoryMapProvider(); provider = plugin.getMemoryMapProvider();
table = provider.getTable(); table = provider.getTable();
model = (MemoryMapModel) table.getModel(); model = provider.getModel();
} }
private Address getAddr(long offset) { private Address getAddr(long offset) {

View file

@ -109,7 +109,8 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
private static final Icon ICON_HOME = new GIcon("icon.filechooser.places.home"); private static final Icon ICON_HOME = new GIcon("icon.filechooser.places.home");
private static final Icon ICON_RECENT = new GIcon("icon.filechooser.places.recent"); private static final Icon ICON_RECENT = new GIcon("icon.filechooser.places.recent");
// base and overlay? private final static Cursor WAIT_CURSOR = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR);
private final static Cursor DEFAULT_CURSOR = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
/** Instruction to display only files. */ /** Instruction to display only files. */
public static final int FILES_ONLY = 0; public static final int FILES_ONLY = 0;
@ -464,13 +465,13 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
@Override @Override
public void mouseEntered(MouseEvent e) { public void mouseEntered(MouseEvent e) {
waitPanel.setCursor(new Cursor(Cursor.WAIT_CURSOR)); waitPanel.setCursor(WAIT_CURSOR);
e.consume(); e.consume();
} }
@Override @Override
public void mouseExited(MouseEvent e) { public void mouseExited(MouseEvent e) {
waitPanel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); waitPanel.setCursor(DEFAULT_CURSOR);
} }
}); });
waitPanel.addMouseMotionListener(new MouseMotionAdapter() { waitPanel.addMouseMotionListener(new MouseMotionAdapter() {

View file

@ -32,8 +32,8 @@ import ghidra.util.task.TaskMonitor;
public class DataTypeArchiveTransformerPanel extends JPanel { public class DataTypeArchiveTransformerPanel extends JPanel {
private final static Cursor WAIT_CURSOR = new Cursor(Cursor.WAIT_CURSOR); private final static Cursor WAIT_CURSOR = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR);
private final static Cursor NORM_CURSOR = new Cursor(Cursor.DEFAULT_CURSOR); private final static Cursor DEFAULT_CURSOR = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
private JPanel filePanel; private JPanel filePanel;
private JTextField oldFileTextField; private JTextField oldFileTextField;
@ -85,7 +85,7 @@ public class DataTypeArchiveTransformerPanel extends JPanel {
oldBrowseButton.addActionListener(e -> { oldBrowseButton.addActionListener(e -> {
setCursor(WAIT_CURSOR); setCursor(WAIT_CURSOR);
File file = chooseFile("Choose old data type archive"); File file = chooseFile("Choose old data type archive");
setCursor(NORM_CURSOR); setCursor(DEFAULT_CURSOR);
if (file != null) { if (file != null) {
oldFileTextField.setText(file.getAbsolutePath()); oldFileTextField.setText(file.getAbsolutePath());
} }
@ -119,7 +119,7 @@ public class DataTypeArchiveTransformerPanel extends JPanel {
newBrowseButton.addActionListener(e -> { newBrowseButton.addActionListener(e -> {
setCursor(WAIT_CURSOR); setCursor(WAIT_CURSOR);
File file = chooseFile("Choose new data type archive"); File file = chooseFile("Choose new data type archive");
setCursor(NORM_CURSOR); setCursor(DEFAULT_CURSOR);
if (file != null) { if (file != null) {
newFileTextField.setText(file.getAbsolutePath()); newFileTextField.setText(file.getAbsolutePath());
} }
@ -148,7 +148,7 @@ public class DataTypeArchiveTransformerPanel extends JPanel {
destinationBrowseButton.addActionListener(e -> { destinationBrowseButton.addActionListener(e -> {
setCursor(WAIT_CURSOR); setCursor(WAIT_CURSOR);
File file = chooseFile("Choose destination file"); File file = chooseFile("Choose destination file");
setCursor(NORM_CURSOR); setCursor(DEFAULT_CURSOR);
if (file != null) { if (file != null) {
destinationFileTextField.setText(file.getAbsolutePath()); destinationFileTextField.setText(file.getAbsolutePath());
} }