mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
GP-3755 - Added filter to the Memory Map provider
This commit is contained in:
parent
b261137b40
commit
6afed33ce0
7 changed files with 276 additions and 281 deletions
|
@ -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> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue