mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
GT-3226 - Symbol Table - Performance improvements - review fixes:
convert SymbolRowObject to Symbol
This commit is contained in:
parent
fc67c6aaeb
commit
9e320c6401
33 changed files with 638 additions and 624 deletions
|
@ -120,9 +120,14 @@ public class RenameLabelCmd implements Command {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
s.setName(newName, source);
|
s.setName(newName, source);
|
||||||
if ((newName.length() != 0 && !newName.equals(s.getName())) ||
|
|
||||||
(newName.length() == 0 && s.getSource() != SourceType.DEFAULT)) {
|
if (newName.length() == 0 && s.getSource() != SourceType.DEFAULT) {
|
||||||
errorMsg = "Rename failed - default names may not be used";
|
errorMsg = "Rename failed - cannot set non-default symbol name to \"\"";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newName.equals(s.getName())) {
|
||||||
|
errorMsg = "Rename failed";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,9 +85,9 @@ class ReferenceProvider extends ComponentProviderAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void symbolRemoved(long symbolID) {
|
void symbolRemoved(Symbol symbol) {
|
||||||
if (isVisible()) {
|
if (isVisible()) {
|
||||||
referenceKeyModel.symbolRemoved(symbolID);
|
referenceKeyModel.symbolRemoved(symbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,5 +157,4 @@ class ReferenceProvider extends ComponentProviderAdapter {
|
||||||
public void updateTitle() {
|
public void updateTitle() {
|
||||||
setSubTitle(generateSubTitle());
|
setSubTitle(generateSubTitle());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,9 +39,9 @@ class SymbolEditor extends DefaultCellEditor {
|
||||||
@Override
|
@Override
|
||||||
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected,
|
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected,
|
||||||
int row, int column) {
|
int row, int column) {
|
||||||
if (value instanceof SymbolTableNameValue) {
|
|
||||||
SymbolTableNameValue cellValue = (SymbolTableNameValue) value;
|
Symbol symbol = (Symbol) value;
|
||||||
Symbol symbol = cellValue.getSymbol();
|
if (symbol != null) {
|
||||||
symbolField.setText(symbol.getName());
|
symbolField.setText(symbol.getName());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -46,8 +46,8 @@ class SymbolPanel extends JPanel {
|
||||||
private GhidraTable symTable;
|
private GhidraTable symTable;
|
||||||
private TableModelListener listener;
|
private TableModelListener listener;
|
||||||
private FilterDialog filterDialog;
|
private FilterDialog filterDialog;
|
||||||
private GhidraThreadedTablePanel<SymbolRowObject> threadedTablePanel;
|
private GhidraThreadedTablePanel<Symbol> threadedTablePanel;
|
||||||
private GhidraTableFilterPanel<SymbolRowObject> tableFilterPanel;
|
private GhidraTableFilterPanel<Symbol> tableFilterPanel;
|
||||||
|
|
||||||
SymbolPanel(SymbolProvider provider, SymbolTableModel model, SymbolRenderer renderer,
|
SymbolPanel(SymbolProvider provider, SymbolTableModel model, SymbolRenderer renderer,
|
||||||
final PluginTool tool, GoToService gotoService) {
|
final PluginTool tool, GoToService gotoService) {
|
||||||
|
@ -116,9 +116,9 @@ class SymbolPanel extends JPanel {
|
||||||
return tableFilterPanel;
|
return tableFilterPanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected RowFilterTransformer<SymbolRowObject> updateRowDataTransformer(boolean nameOnly) {
|
protected RowFilterTransformer<Symbol> updateRowDataTransformer(boolean nameOnly) {
|
||||||
if (nameOnly) {
|
if (nameOnly) {
|
||||||
return new NameOnlyRowTransformer(tableModel);
|
return new NameOnlyRowTransformer();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new DefaultRowFilterTransformer<>(tableModel, symTable.getColumnModel());
|
return new DefaultRowFilterTransformer<>(tableModel, symTable.getColumnModel());
|
||||||
|
@ -185,7 +185,7 @@ class SymbolPanel extends JPanel {
|
||||||
return symTable.getRowCount();
|
return symTable.getRowCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<SymbolRowObject> getSelectedSymbolKeys() {
|
List<Symbol> getSelectedSymbolKeys() {
|
||||||
int[] rows = symTable.getSelectedRows();
|
int[] rows = symTable.getSelectedRows();
|
||||||
return tableModel.getRowObjects(rows);
|
return tableModel.getRowObjects(rows);
|
||||||
}
|
}
|
||||||
|
@ -198,21 +198,16 @@ class SymbolPanel extends JPanel {
|
||||||
// Inner Classes
|
// Inner Classes
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
private static class NameOnlyRowTransformer implements RowFilterTransformer<SymbolRowObject> {
|
private static class NameOnlyRowTransformer implements RowFilterTransformer<Symbol> {
|
||||||
private List<String> list = new ArrayList<>();
|
private List<String> list = new ArrayList<>();
|
||||||
private SymbolTableModel model;
|
|
||||||
|
|
||||||
NameOnlyRowTransformer(SymbolTableModel model) {
|
|
||||||
this.model = model;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> transform(SymbolRowObject rowObject) {
|
public List<String> transform(Symbol rowObject) {
|
||||||
list.clear();
|
list.clear();
|
||||||
Object value = model.getColumnValueForRow(rowObject, SymbolTableModel.LABEL_COL);
|
if (rowObject != null) {
|
||||||
if (value != null) {
|
// The toString() returns the name for the symbol, which may be cached. Calling
|
||||||
// the toString() returns the value for the symbol, which may be cached
|
// toString() will also avoid locking for cached values.
|
||||||
list.add(value.toString());
|
list.add(rowObject.toString());
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,17 +74,18 @@ class SymbolProvider extends ComponentProviderAdapter {
|
||||||
if (program == null) {
|
if (program == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
List<SymbolRowObject> rowObjects = symbolPanel.getSelectedSymbolKeys();
|
|
||||||
|
List<Symbol> rowObjects = symbolPanel.getSelectedSymbolKeys();
|
||||||
long[] symbolIDs = new long[rowObjects.size()];
|
long[] symbolIDs = new long[rowObjects.size()];
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (SymbolRowObject obj : rowObjects) {
|
for (Symbol obj : rowObjects) {
|
||||||
symbolIDs[index++] = obj.getKey();
|
symbolIDs[index++] = obj.getID();
|
||||||
}
|
}
|
||||||
return new ProgramSymbolActionContext(this, program, symbolIDs, getTable());
|
return new ProgramSymbolActionContext(this, program, symbolIDs, getTable());
|
||||||
}
|
}
|
||||||
|
|
||||||
void deleteSymbols() {
|
void deleteSymbols() {
|
||||||
List<SymbolRowObject> rowObjects = symbolPanel.getSelectedSymbolKeys();
|
List<Symbol> rowObjects = symbolPanel.getSelectedSymbolKeys();
|
||||||
symbolKeyModel.delete(rowObjects);
|
symbolKeyModel.delete(rowObjects);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,15 +94,15 @@ class SymbolProvider extends ComponentProviderAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol getCurrentSymbol() {
|
Symbol getCurrentSymbol() {
|
||||||
List<SymbolRowObject> rowObjects = symbolPanel.getSelectedSymbolKeys();
|
List<Symbol> rowObjects = symbolPanel.getSelectedSymbolKeys();
|
||||||
if (rowObjects != null && rowObjects.size() >= 1) {
|
if (rowObjects != null && rowObjects.size() >= 1) {
|
||||||
return symbolKeyModel.getSymbol(rowObjects.get(0).getKey());
|
return rowObjects.get(0);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol getSymbolForRow(int row) {
|
Symbol getSymbolForRow(int row) {
|
||||||
return symbolKeyModel.getRowObject(row).getSymbol();
|
return symbolKeyModel.getRowObject(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setCurrentSymbol(Symbol symbol) {
|
void setCurrentSymbol(Symbol symbol) {
|
||||||
|
@ -136,12 +137,6 @@ class SymbolProvider extends ComponentProviderAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void symbolRemoved(long symbolId) {
|
|
||||||
if (isVisible()) {
|
|
||||||
symbolKeyModel.symbolRemoved(symbolId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void symbolChanged(Symbol s) {
|
void symbolChanged(Symbol s) {
|
||||||
if (isVisible()) {
|
if (isVisible()) {
|
||||||
symbolKeyModel.symbolChanged(s);
|
symbolKeyModel.symbolChanged(s);
|
||||||
|
|
|
@ -131,8 +131,8 @@ public class SymbolReferenceModel extends AddressBasedTableModel<Reference> {
|
||||||
checkRefs(symbol);
|
checkRefs(symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
void symbolRemoved(long symbolID) {
|
void symbolRemoved(Symbol symbol) {
|
||||||
if (currentSymbol != null && currentSymbol.getID() == symbolID) {
|
if (currentSymbol != null && currentSymbol.getID() == symbol.getID()) {
|
||||||
setCurrentSymbol(null);
|
setCurrentSymbol(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,10 +52,6 @@ class SymbolRenderer extends GhidraTableCellRenderer {
|
||||||
if (value == null && column == SymbolTableModel.LABEL_COL) {
|
if (value == null && column == SymbolTableModel.LABEL_COL) {
|
||||||
setText("<< REMOVED >>");
|
setText("<< REMOVED >>");
|
||||||
}
|
}
|
||||||
else if (value instanceof SymbolTableNameValue) {
|
|
||||||
Symbol symbol = ((SymbolTableNameValue) value).getSymbol();
|
|
||||||
handleSymbol(symbol, isSelected);
|
|
||||||
}
|
|
||||||
else if (value instanceof Symbol) {
|
else if (value instanceof Symbol) {
|
||||||
handleSymbol(value, isSelected);
|
handleSymbol(value, isSelected);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
/* ###
|
|
||||||
* IP: GHIDRA
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package ghidra.app.plugin.core.symtable;
|
|
||||||
|
|
||||||
import ghidra.program.model.symbol.Symbol;
|
|
||||||
|
|
||||||
class SymbolRowObject implements Comparable<SymbolRowObject> {
|
|
||||||
|
|
||||||
// symbol can be null after it is deleted
|
|
||||||
private final Symbol symbol;
|
|
||||||
private final long key;
|
|
||||||
|
|
||||||
SymbolRowObject(Symbol s) {
|
|
||||||
this.symbol = s;
|
|
||||||
this.key = s.getID();
|
|
||||||
}
|
|
||||||
|
|
||||||
// this constructor is used to create a row object to serve as a key for deleting items
|
|
||||||
// in the model after a symbol has been deleted
|
|
||||||
SymbolRowObject(long symbolId) {
|
|
||||||
this.symbol = null;
|
|
||||||
this.key = symbolId;
|
|
||||||
}
|
|
||||||
|
|
||||||
Symbol getSymbol() {
|
|
||||||
return symbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
long getKey() {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
final int prime = 31;
|
|
||||||
int result = 1;
|
|
||||||
result = prime * result + (int) (key ^ (key >>> 32));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (this == obj) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (obj == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (getClass() != obj.getClass()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
SymbolRowObject other = (SymbolRowObject) obj;
|
|
||||||
if (key != other.key) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compareTo(SymbolRowObject o) {
|
|
||||||
return ((Long) key).compareTo(o.key);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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.
|
||||||
|
@ -20,21 +19,17 @@ import ghidra.framework.plugintool.ServiceProvider;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.symbol.Symbol;
|
import ghidra.program.model.symbol.Symbol;
|
||||||
import ghidra.program.model.symbol.SymbolTable;
|
|
||||||
import ghidra.util.table.ProgramLocationTableRowMapper;
|
import ghidra.util.table.ProgramLocationTableRowMapper;
|
||||||
|
|
||||||
public class SymbolRowObjectToAddressTableRowMapper extends
|
public class SymbolRowObjectToAddressTableRowMapper
|
||||||
ProgramLocationTableRowMapper<SymbolRowObject, Address> {
|
extends ProgramLocationTableRowMapper<Symbol, Address> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address map(SymbolRowObject rowObject, Program data, ServiceProvider serviceProvider) {
|
public Address map(Symbol rowObject, Program data, ServiceProvider serviceProvider) {
|
||||||
SymbolTable symbolTable = data.getSymbolTable();
|
if (rowObject == null) {
|
||||||
Symbol symbol = symbolTable.getSymbol(rowObject.getKey());
|
|
||||||
if (symbol == null) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
return rowObject.getAddress();
|
||||||
return symbol.getAddress();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -19,23 +18,15 @@ package ghidra.app.plugin.core.symtable;
|
||||||
import ghidra.framework.plugintool.ServiceProvider;
|
import ghidra.framework.plugintool.ServiceProvider;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.symbol.Symbol;
|
import ghidra.program.model.symbol.Symbol;
|
||||||
import ghidra.program.model.symbol.SymbolTable;
|
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.util.table.ProgramLocationTableRowMapper;
|
import ghidra.util.table.ProgramLocationTableRowMapper;
|
||||||
|
|
||||||
public class SymbolRowObjectToProgramLocationTableRowMapper extends
|
public class SymbolRowObjectToProgramLocationTableRowMapper
|
||||||
ProgramLocationTableRowMapper<SymbolRowObject, ProgramLocation> {
|
extends ProgramLocationTableRowMapper<Symbol, ProgramLocation> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProgramLocation map(SymbolRowObject rowObject, Program data,
|
public ProgramLocation map(Symbol rowObject, Program data, ServiceProvider serviceProvider) {
|
||||||
ServiceProvider serviceProvider) {
|
return rowObject.getProgramLocation();
|
||||||
SymbolTable symbolTable = data.getSymbolTable();
|
|
||||||
Symbol symbol = symbolTable.getSymbol(rowObject.getKey());
|
|
||||||
if (symbol == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return symbol.getProgramLocation();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.symtable;
|
package ghidra.app.plugin.core.symtable;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import docking.widgets.table.*;
|
import docking.widgets.table.*;
|
||||||
import ghidra.app.cmd.function.DeleteFunctionCmd;
|
import ghidra.app.cmd.function.DeleteFunctionCmd;
|
||||||
|
@ -41,7 +40,12 @@ import ghidra.util.table.column.*;
|
||||||
import ghidra.util.table.field.*;
|
import ghidra.util.table.field.*;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
class SymbolTableModel extends AddressBasedTableModel<Symbol> {
|
||||||
|
|
||||||
|
private static final Comparator<Symbol> NAME_COL_COMPARATOR = (s1, s2) -> {
|
||||||
|
return s1.toString().compareToIgnoreCase(s2.toString());
|
||||||
|
};
|
||||||
|
|
||||||
static final int LABEL_COL = 0;
|
static final int LABEL_COL = 0;
|
||||||
static final int LOCATION_COL = 1;
|
static final int LOCATION_COL = 1;
|
||||||
static final int TYPE_COL = 2;
|
static final int TYPE_COL = 2;
|
||||||
|
@ -62,17 +66,14 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
this.tool = tool;
|
this.tool = tool;
|
||||||
this.filter = new NewSymbolFilter();
|
this.filter = new NewSymbolFilter();
|
||||||
|
|
||||||
// leave off default sorting, as this can be slow; the user can sort as desired
|
|
||||||
setDefaultTableSortState(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TableColumnDescriptor<SymbolRowObject> createTableColumnDescriptor() {
|
protected TableColumnDescriptor<Symbol> createTableColumnDescriptor() {
|
||||||
TableColumnDescriptor<SymbolRowObject> descriptor = new TableColumnDescriptor<>();
|
TableColumnDescriptor<Symbol> descriptor = new TableColumnDescriptor<>();
|
||||||
|
|
||||||
descriptor.addVisibleColumn(new NameTableColumn(), 1, true);
|
descriptor.addVisibleColumn(new NameTableColumn());
|
||||||
descriptor.addVisibleColumn(new LocationTableColumn());
|
descriptor.addVisibleColumn(new LocationTableColumn(), 1, true);
|
||||||
descriptor.addVisibleColumn(new SymbolTypeTableColumn());
|
descriptor.addVisibleColumn(new SymbolTypeTableColumn());
|
||||||
descriptor.addHiddenColumn(new DataTypeTableColumn());
|
descriptor.addHiddenColumn(new DataTypeTableColumn());
|
||||||
descriptor.addVisibleColumn(new NamespaceTableColumn());
|
descriptor.addVisibleColumn(new NamespaceTableColumn());
|
||||||
|
@ -136,7 +137,7 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doLoad(Accumulator<SymbolRowObject> accumulator, TaskMonitor monitor)
|
protected void doLoad(Accumulator<Symbol> accumulator, TaskMonitor monitor)
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
if (symbolTable == null) {
|
if (symbolTable == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -156,7 +157,7 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
monitor.checkCanceled();
|
monitor.checkCanceled();
|
||||||
Symbol s = it.next();
|
Symbol s = it.next();
|
||||||
if (filter.accepts(s, getProgram())) {
|
if (filter.accepts(s, getProgram())) {
|
||||||
accumulator.add(new SymbolRowObject(s));
|
accumulator.add(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (filter.acceptsDefaultLabelSymbols()) {
|
if (filter.acceptsDefaultLabelSymbols()) {
|
||||||
|
@ -168,7 +169,7 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
Address a = addrIt.next();
|
Address a = addrIt.next();
|
||||||
Symbol s = symbolTable.getPrimarySymbol(a);
|
Symbol s = symbolTable.getPrimarySymbol(a);
|
||||||
if (s.isDynamic() && filter.accepts(s, getProgram())) {
|
if (s.isDynamic() && filter.accepts(s, getProgram())) {
|
||||||
accumulator.add(new SymbolRowObject(s));
|
accumulator.add(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,8 +194,7 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolRowObject rowObject = filteredData.get(row);
|
Symbol symbol = filteredData.get(row);
|
||||||
Symbol symbol = symbolTable.getSymbol(rowObject.getKey());
|
|
||||||
if (symbol == null) {
|
if (symbol == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -215,9 +215,9 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProgramLocation getProgramLocation(int row, int column) {
|
public ProgramLocation getProgramLocation(int row, int column) {
|
||||||
SymbolTableNameValue s = (SymbolTableNameValue) getValueAt(row, LABEL_COL);
|
Symbol s = (Symbol) getValueAt(row, LABEL_COL);
|
||||||
if (s != null) {
|
if (s != null) {
|
||||||
return s.getSymbol().getProgramLocation();
|
return s.getProgramLocation();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -246,7 +246,7 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
|
|
||||||
void symbolAdded(Symbol s) {
|
void symbolAdded(Symbol s) {
|
||||||
if (filter.accepts(s, getProgram())) {
|
if (filter.accepts(s, getProgram())) {
|
||||||
addObject(new SymbolRowObject(s));
|
addObject(s);
|
||||||
lastSymbol = s;
|
lastSymbol = s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -255,27 +255,20 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
if (lastSymbol != null && lastSymbol.getID() == s.getID()) {
|
if (lastSymbol != null && lastSymbol.getID() == s.getID()) {
|
||||||
lastSymbol = null;
|
lastSymbol = null;
|
||||||
}
|
}
|
||||||
removeObject(new SymbolRowObject(s));
|
removeObject(s);
|
||||||
}
|
|
||||||
|
|
||||||
void symbolRemoved(long symbolId) {
|
|
||||||
if (lastSymbol != null && lastSymbol.getID() == symbolId) {
|
|
||||||
lastSymbol = null;
|
|
||||||
}
|
|
||||||
removeObject(new SymbolRowObject(symbolId));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void symbolChanged(Symbol s) {
|
void symbolChanged(Symbol s) {
|
||||||
SymbolRowObject symbolRowObject = new SymbolRowObject(s);
|
Symbol Symbol = s;
|
||||||
if (filter.accepts(s, getProgram())) {
|
if (filter.accepts(s, getProgram())) {
|
||||||
updateObject(symbolRowObject);
|
updateObject(Symbol);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
removeObject(symbolRowObject);
|
removeObject(Symbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void delete(List<SymbolRowObject> rowObjects) {
|
void delete(List<Symbol> rowObjects) {
|
||||||
if (rowObjects == null || rowObjects.size() == 0) {
|
if (rowObjects == null || rowObjects.size() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -283,11 +276,7 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
tool.setStatusInfo("");
|
tool.setStatusInfo("");
|
||||||
List<Symbol> deleteList = new LinkedList<>();
|
List<Symbol> deleteList = new LinkedList<>();
|
||||||
CompoundCmd cmd = new CompoundCmd("Delete symbol(s)");
|
CompoundCmd cmd = new CompoundCmd("Delete symbol(s)");
|
||||||
for (int i = 0; i < rowObjects.size(); i++) {
|
for (Symbol symbol : rowObjects) {
|
||||||
Symbol symbol = symbolTable.getSymbol(rowObjects.get(i).getKey());
|
|
||||||
if (symbol == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (symbol.isDynamic()) {
|
if (symbol.isDynamic()) {
|
||||||
Symbol[] symbols = symbolTable.getSymbols(symbol.getAddress());
|
Symbol[] symbols = symbolTable.getSymbols(symbol.getAddress());
|
||||||
if (symbols.length == 1) {
|
if (symbols.length == 1) {
|
||||||
|
@ -296,7 +285,7 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteList.add(rowObjects.get(i).getSymbol());
|
deleteList.add(symbol);
|
||||||
String label = symbol.getName();
|
String label = symbol.getName();
|
||||||
if (symbol.getSymbolType() == SymbolType.FUNCTION) {
|
if (symbol.getSymbolType() == SymbolType.FUNCTION) {
|
||||||
Function function = (Function) symbol.getObject();
|
Function function = (Function) symbol.getObject();
|
||||||
|
@ -316,9 +305,10 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
if (cmd.size() == 0) {
|
if (cmd.size() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tool.execute(cmd, getProgram())) {
|
if (tool.execute(cmd, getProgram())) {
|
||||||
for (int k = 0; k < deleteList.size(); k++) {
|
for (Symbol s : deleteList) {
|
||||||
removeObject(new SymbolRowObject(deleteList.get(k)));
|
removeObject(s);
|
||||||
}
|
}
|
||||||
updateNow();
|
updateNow();
|
||||||
}
|
}
|
||||||
|
@ -334,15 +324,14 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address getAddress(int row) {
|
public Address getAddress(int row) {
|
||||||
Symbol symbol = symbolTable.getSymbol(getRowObject(row).getKey());
|
Symbol symbol = getRowObject(row);
|
||||||
if (symbol == null) {
|
if (symbol == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return symbol.getAddress();
|
return symbol.getAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
private AddressBasedLocation getSymbolLocation(SymbolRowObject rowObject) {
|
private AddressBasedLocation getSymbolLocation(Symbol s) {
|
||||||
Symbol s = rowObject.getSymbol();
|
|
||||||
if (s == null) {
|
if (s == null) {
|
||||||
return new AddressBasedLocation();
|
return new AddressBasedLocation();
|
||||||
}
|
}
|
||||||
|
@ -350,17 +339,36 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
if (type == SymbolType.PARAMETER || type == SymbolType.LOCAL_VAR) {
|
if (type == SymbolType.PARAMETER || type == SymbolType.LOCAL_VAR) {
|
||||||
// Must use special location object for variables which renders variable storage
|
// Must use special location object for variables which renders variable storage
|
||||||
// location since this can't be obtained from just a variable storage address
|
// location since this can't be obtained from just a variable storage address
|
||||||
return new VariableSymbolLocation((Variable) s.getObject());
|
Variable object = (Variable) s.getObject();
|
||||||
|
if (object == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new VariableSymbolLocation(object);
|
||||||
}
|
}
|
||||||
return new AddressBasedLocation(program, s.getAddress());
|
return new AddressBasedLocation(program, s.getAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Comparator<Symbol> createSortComparator(int columnIndex) {
|
||||||
|
DynamicTableColumn<Symbol, ?, ?> column = getColumn(columnIndex);
|
||||||
|
if (column instanceof NameTableColumn) {
|
||||||
|
// note: we use our own name comparator to increase sorting speed for the name
|
||||||
|
// column. This works because this comparator is called for each *row object*
|
||||||
|
// allowing the comparator to compare the Symbols based on name instead of
|
||||||
|
// having to use the table model's code for getting a column value for the
|
||||||
|
// row object. The code for retrieving a column value is slower than just
|
||||||
|
// working with the row object directly. See
|
||||||
|
// ThreadedTableModel.getCachedColumnValueForRow for more info.
|
||||||
|
return NAME_COL_COMPARATOR;
|
||||||
|
}
|
||||||
|
return super.createSortComparator(columnIndex);
|
||||||
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// Table Column Classes
|
// Table Column Classes
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
private class NameTableColumn
|
private class NameTableColumn extends AbstractProgramBasedDynamicTableColumn<Symbol, Symbol> {
|
||||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, SymbolTableNameValue> {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getColumnName() {
|
public String getColumnName() {
|
||||||
|
@ -368,25 +376,18 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SymbolTableNameValue getValue(SymbolRowObject rowObject, Settings settings,
|
public Symbol getValue(Symbol symbol, Settings settings, Program p,
|
||||||
Program p, ServiceProvider svcProvider) throws IllegalArgumentException {
|
ServiceProvider svcProvider) throws IllegalArgumentException {
|
||||||
|
|
||||||
Symbol s = rowObject.getSymbol();
|
if (!symbol.checkIsValid()) {
|
||||||
if (s == null) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
return symbol;
|
||||||
// Note: this call is slow, especially for dynamic symbols. Caching the dynamic
|
|
||||||
// symbols in the SymbolRowObject *greatly* increases sorting and filtering performance.
|
|
||||||
// For now we assume that most users are not loading dynamic labels. If we add
|
|
||||||
// caching, then we have to deal with the stickiness of when to clear/update the cache
|
|
||||||
String name = s.toString();
|
|
||||||
return new SymbolTableNameValue(s, name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PinnedTableColumn
|
private class PinnedTableColumn
|
||||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, Boolean> {
|
extends AbstractProgramBasedDynamicTableColumn<Symbol, Boolean> {
|
||||||
|
|
||||||
private PinnedRenderer renderer = new PinnedRenderer();
|
private PinnedRenderer renderer = new PinnedRenderer();
|
||||||
|
|
||||||
|
@ -396,10 +397,10 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean getValue(SymbolRowObject rowObject, Settings settings, Program p,
|
public Boolean getValue(Symbol symbol, Settings settings, Program p,
|
||||||
ServiceProvider svcProvider) throws IllegalArgumentException {
|
ServiceProvider svcProvider) throws IllegalArgumentException {
|
||||||
Symbol symbol = rowObject.getSymbol();
|
|
||||||
if (symbol == null) {
|
if (!symbol.checkIsValid()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return symbol.isPinned();
|
return symbol.isPinned();
|
||||||
|
@ -417,7 +418,7 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private class LocationTableColumn
|
private class LocationTableColumn
|
||||||
extends AbstractProgramLocationTableColumn<SymbolRowObject, AddressBasedLocation> {
|
extends AbstractProgramLocationTableColumn<Symbol, AddressBasedLocation> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getColumnName() {
|
public String getColumnName() {
|
||||||
|
@ -425,16 +426,16 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AddressBasedLocation getValue(SymbolRowObject rowObject, Settings settings,
|
public AddressBasedLocation getValue(Symbol symbol, Settings settings, Program p,
|
||||||
Program p, ServiceProvider svcProvider) throws IllegalArgumentException {
|
ServiceProvider svcProvider) throws IllegalArgumentException {
|
||||||
return getSymbolLocation(rowObject);
|
return getSymbolLocation(symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProgramLocation getProgramLocation(SymbolRowObject rowObject, Settings settings,
|
public ProgramLocation getProgramLocation(Symbol symbol, Settings settings, Program p,
|
||||||
Program p, ServiceProvider svcProvider) {
|
ServiceProvider svcProvider) {
|
||||||
Symbol symbol = rowObject.getSymbol();
|
|
||||||
if (symbol == null) {
|
if (!symbol.checkIsValid()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return symbol.getProgramLocation();
|
return symbol.getProgramLocation();
|
||||||
|
@ -442,7 +443,7 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SymbolTypeTableColumn
|
private class SymbolTypeTableColumn
|
||||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, String> {
|
extends AbstractProgramBasedDynamicTableColumn<Symbol, String> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getColumnName() {
|
public String getColumnName() {
|
||||||
|
@ -450,17 +451,16 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getValue(SymbolRowObject rowObject, Settings settings, Program p,
|
public String getValue(Symbol symbol, Settings settings, Program p,
|
||||||
ServiceProvider svcProvider) throws IllegalArgumentException {
|
ServiceProvider svcProvider) throws IllegalArgumentException {
|
||||||
|
|
||||||
Symbol s = rowObject.getSymbol();
|
if (!symbol.checkIsValid()) {
|
||||||
if (s == null) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: this call is slow. If we decide that filtering/sorting on this value is
|
// Note: this call is slow. If we decide that filtering/sorting on this value is
|
||||||
// important, then this should be cached
|
// important, then this should be cached
|
||||||
return SymbolUtilities.getSymbolTypeDisplayName(s);
|
return SymbolUtilities.getSymbolTypeDisplayName(symbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -472,7 +472,7 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DataTypeTableColumn
|
private class DataTypeTableColumn
|
||||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, String> {
|
extends AbstractProgramBasedDynamicTableColumn<Symbol, String> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getColumnName() {
|
public String getColumnName() {
|
||||||
|
@ -480,11 +480,10 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getValue(SymbolRowObject rowObject, Settings settings, Program p,
|
public String getValue(Symbol symbol, Settings settings, Program p,
|
||||||
ServiceProvider svcProvider) throws IllegalArgumentException {
|
ServiceProvider svcProvider) throws IllegalArgumentException {
|
||||||
|
|
||||||
Symbol symbol = rowObject.getSymbol();
|
if (!symbol.checkIsValid()) {
|
||||||
if (symbol == null) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -510,7 +509,7 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private class NamespaceTableColumn
|
private class NamespaceTableColumn
|
||||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, String> {
|
extends AbstractProgramBasedDynamicTableColumn<Symbol, String> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getColumnName() {
|
public String getColumnName() {
|
||||||
|
@ -518,19 +517,18 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getValue(SymbolRowObject rowObject, Settings settings, Program p,
|
public String getValue(Symbol symbol, Settings settings, Program p,
|
||||||
ServiceProvider svcProvider) throws IllegalArgumentException {
|
ServiceProvider svcProvider) throws IllegalArgumentException {
|
||||||
Symbol symbol = rowObject.getSymbol();
|
|
||||||
if (symbol == null) {
|
if (!symbol.checkIsValid()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return symbol.getParentNamespace().getName(true);
|
return symbol.getParentNamespace().getName(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SourceTableColumn
|
private class SourceTableColumn
|
||||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, SourceType> {
|
extends AbstractProgramBasedDynamicTableColumn<Symbol, SourceType> {
|
||||||
|
|
||||||
private GColumnRenderer<SourceType> renderer = new AbstractGColumnRenderer<SourceType>() {
|
private GColumnRenderer<SourceType> renderer = new AbstractGColumnRenderer<SourceType>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -558,9 +556,9 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SourceType getValue(SymbolRowObject rowObject, Settings settings, Program p,
|
public SourceType getValue(Symbol symbol, Settings settings, Program p,
|
||||||
ServiceProvider svcProvider) throws IllegalArgumentException {
|
ServiceProvider svcProvider) throws IllegalArgumentException {
|
||||||
Symbol symbol = rowObject.getSymbol();
|
|
||||||
if (symbol == null) {
|
if (symbol == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -570,7 +568,7 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ReferenceCountTableColumn
|
private class ReferenceCountTableColumn
|
||||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, Integer> {
|
extends AbstractProgramBasedDynamicTableColumn<Symbol, Integer> {
|
||||||
|
|
||||||
private ReferenceCountRenderer renderer = new ReferenceCountRenderer();
|
private ReferenceCountRenderer renderer = new ReferenceCountRenderer();
|
||||||
|
|
||||||
|
@ -580,13 +578,11 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer getValue(SymbolRowObject rowObject, Settings settings, Program p,
|
public Integer getValue(Symbol symbol, Settings settings, Program p,
|
||||||
ServiceProvider svcProvider) throws IllegalArgumentException {
|
ServiceProvider svcProvider) throws IllegalArgumentException {
|
||||||
Symbol symbol = rowObject.getSymbol();
|
if (!symbol.checkIsValid()) {
|
||||||
if (symbol == null) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Integer.valueOf(symbol.getReferenceCount());
|
return Integer.valueOf(symbol.getReferenceCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -604,7 +600,7 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private class OffcutReferenceCountTableColumn
|
private class OffcutReferenceCountTableColumn
|
||||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, Integer> {
|
extends AbstractProgramBasedDynamicTableColumn<Symbol, Integer> {
|
||||||
|
|
||||||
private OffcutReferenceCountRenderer renderer = new OffcutReferenceCountRenderer();
|
private OffcutReferenceCountRenderer renderer = new OffcutReferenceCountRenderer();
|
||||||
|
|
||||||
|
@ -614,11 +610,9 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer getValue(SymbolRowObject rowObject, Settings settings, Program p,
|
public Integer getValue(Symbol symbol, Settings settings, Program p,
|
||||||
ServiceProvider svcProvider) throws IllegalArgumentException {
|
ServiceProvider svcProvider) throws IllegalArgumentException {
|
||||||
|
if (!symbol.checkIsValid()) {
|
||||||
Symbol symbol = rowObject.getSymbol();
|
|
||||||
if (symbol == null) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -655,8 +649,7 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class UserTableColumn
|
private class UserTableColumn extends AbstractProgramBasedDynamicTableColumn<Symbol, String> {
|
||||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, String> {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getColumnName() {
|
public String getColumnName() {
|
||||||
|
@ -669,11 +662,10 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getValue(SymbolRowObject rowObject, Settings settings, Program p,
|
public String getValue(Symbol symbol, Settings settings, Program p,
|
||||||
ServiceProvider svcProvider) throws IllegalArgumentException {
|
ServiceProvider svcProvider) throws IllegalArgumentException {
|
||||||
|
|
||||||
Symbol symbol = rowObject.getSymbol();
|
if (!symbol.checkIsValid()) {
|
||||||
if (symbol == null) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -694,7 +686,7 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private class OriginalNameColumn
|
private class OriginalNameColumn
|
||||||
extends AbstractProgramBasedDynamicTableColumn<SymbolRowObject, String> {
|
extends AbstractProgramBasedDynamicTableColumn<Symbol, String> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getColumnName() {
|
public String getColumnName() {
|
||||||
|
@ -707,13 +699,17 @@ class SymbolTableModel extends AddressBasedTableModel<SymbolRowObject> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getValue(SymbolRowObject rowObject, Settings settings, Program p,
|
public String getValue(Symbol symbol, Settings settings, Program p,
|
||||||
ServiceProvider svcProvider) throws IllegalArgumentException {
|
ServiceProvider svcProvider) throws IllegalArgumentException {
|
||||||
|
|
||||||
Symbol symbol = rowObject.getSymbol();
|
if (!symbol.checkIsValid()) {
|
||||||
if (symbol == null || !symbol.isExternal()) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!symbol.isExternal()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
SymbolType symbolType = symbol.getSymbolType();
|
SymbolType symbolType = symbol.getSymbolType();
|
||||||
if (symbolType != SymbolType.FUNCTION && symbolType != SymbolType.LABEL) {
|
if (symbolType != SymbolType.FUNCTION && symbolType != SymbolType.LABEL) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
/* ###
|
|
||||||
* IP: GHIDRA
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package ghidra.app.plugin.core.symtable;
|
|
||||||
|
|
||||||
import ghidra.program.model.symbol.Symbol;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A simple data object for the Name column table cell. This class allows us to control
|
|
||||||
* how sorting is performed by caching the slow (potentially) to calculate symbol name.
|
|
||||||
*/
|
|
||||||
class SymbolTableNameValue implements Comparable<SymbolTableNameValue> {
|
|
||||||
|
|
||||||
private Symbol symbol;
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
SymbolTableNameValue(Symbol symbol, String name) {
|
|
||||||
this.symbol = symbol;
|
|
||||||
this.name = name;
|
|
||||||
|
|
||||||
// name will be non-null when cached by the table model
|
|
||||||
if (name == null) {
|
|
||||||
name = symbol.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Symbol getSymbol() {
|
|
||||||
return symbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compareTo(SymbolTableNameValue o) {
|
|
||||||
return name.compareToIgnoreCase(o.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -37,8 +37,7 @@ import ghidra.framework.plugintool.util.PluginStatus;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.listing.Data;
|
import ghidra.program.model.listing.Data;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.symbol.Reference;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.program.model.symbol.Symbol;
|
|
||||||
import ghidra.program.util.ChangeManager;
|
import ghidra.program.util.ChangeManager;
|
||||||
import ghidra.program.util.ProgramChangeRecord;
|
import ghidra.program.util.ProgramChangeRecord;
|
||||||
import ghidra.util.table.GhidraTable;
|
import ghidra.util.table.GhidraTable;
|
||||||
|
@ -210,11 +209,12 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||||
|
|
||||||
ProgramChangeRecord rec = (ProgramChangeRecord) doRecord;
|
ProgramChangeRecord rec = (ProgramChangeRecord) doRecord;
|
||||||
Symbol symbol = null;
|
Symbol symbol = null;
|
||||||
|
SymbolTable symbolTable = currentProgram.getSymbolTable();
|
||||||
switch (eventType) {
|
switch (eventType) {
|
||||||
case ChangeManager.DOCR_CODE_ADDED:
|
case ChangeManager.DOCR_CODE_ADDED:
|
||||||
case ChangeManager.DOCR_CODE_REMOVED:
|
case ChangeManager.DOCR_CODE_REMOVED:
|
||||||
if (rec.getNewValue() instanceof Data) {
|
if (rec.getNewValue() instanceof Data) {
|
||||||
symbol = currentProgram.getSymbolTable().getPrimarySymbol(rec.getStart());
|
symbol = symbolTable.getPrimarySymbol(rec.getStart());
|
||||||
if (symbol != null && symbol.isDynamic()) {
|
if (symbol != null && symbol.isDynamic()) {
|
||||||
symProvider.symbolChanged(symbol);
|
symProvider.symbolChanged(symbol);
|
||||||
refProvider.symbolChanged(symbol);
|
refProvider.symbolChanged(symbol);
|
||||||
|
@ -224,7 +224,7 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||||
|
|
||||||
case ChangeManager.DOCR_SYMBOL_ADDED:
|
case ChangeManager.DOCR_SYMBOL_ADDED:
|
||||||
Address addAddr = rec.getStart();
|
Address addAddr = rec.getStart();
|
||||||
Symbol primaryAtAdd = currentProgram.getSymbolTable().getPrimarySymbol(addAddr);
|
Symbol primaryAtAdd = symbolTable.getPrimarySymbol(addAddr);
|
||||||
if (primaryAtAdd != null && primaryAtAdd.isDynamic()) {
|
if (primaryAtAdd != null && primaryAtAdd.isDynamic()) {
|
||||||
symProvider.symbolRemoved(primaryAtAdd);
|
symProvider.symbolRemoved(primaryAtAdd);
|
||||||
}
|
}
|
||||||
|
@ -236,10 +236,11 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||||
case ChangeManager.DOCR_SYMBOL_REMOVED:
|
case ChangeManager.DOCR_SYMBOL_REMOVED:
|
||||||
Address removeAddr = rec.getStart();
|
Address removeAddr = rec.getStart();
|
||||||
Long symbolID = (Long) rec.getNewValue();
|
Long symbolID = (Long) rec.getNewValue();
|
||||||
symProvider.symbolRemoved(symbolID.longValue());
|
Symbol removedSymbol =
|
||||||
refProvider.symbolRemoved(symbolID.longValue());
|
symbolTable.createSymbolPlaceholder(removeAddr, symbolID);
|
||||||
Symbol primaryAtRemove =
|
symProvider.symbolRemoved(removedSymbol);
|
||||||
currentProgram.getSymbolTable().getPrimarySymbol(removeAddr);
|
refProvider.symbolRemoved(removedSymbol);
|
||||||
|
Symbol primaryAtRemove = symbolTable.getPrimarySymbol(removeAddr);
|
||||||
if (primaryAtRemove != null && primaryAtRemove.isDynamic()) {
|
if (primaryAtRemove != null && primaryAtRemove.isDynamic()) {
|
||||||
symProvider.symbolAdded(primaryAtRemove);
|
symProvider.symbolAdded(primaryAtRemove);
|
||||||
}
|
}
|
||||||
|
@ -274,7 +275,7 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||||
break;
|
break;
|
||||||
case ChangeManager.DOCR_MEM_REFERENCE_ADDED:
|
case ChangeManager.DOCR_MEM_REFERENCE_ADDED:
|
||||||
Reference ref = (Reference) rec.getObject();
|
Reference ref = (Reference) rec.getObject();
|
||||||
symbol = currentProgram.getSymbolTable().getSymbol(ref);
|
symbol = symbolTable.getSymbol(ref);
|
||||||
if (symbol != null) {
|
if (symbol != null) {
|
||||||
symProvider.symbolChanged(symbol);
|
symProvider.symbolChanged(symbol);
|
||||||
refProvider.symbolChanged(symbol);
|
refProvider.symbolChanged(symbol);
|
||||||
|
@ -284,11 +285,12 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||||
ref = (Reference) rec.getObject();
|
ref = (Reference) rec.getObject();
|
||||||
Address toAddr = ref.getToAddress();
|
Address toAddr = ref.getToAddress();
|
||||||
if (toAddr.isMemoryAddress()) {
|
if (toAddr.isMemoryAddress()) {
|
||||||
symbol = currentProgram.getSymbolTable().getSymbol(ref);
|
symbol = symbolTable.getSymbol(ref);
|
||||||
if (symbol == null) {
|
if (symbol == null) {
|
||||||
long id = currentProgram.getSymbolTable().getDynamicSymbolID(
|
|
||||||
ref.getToAddress());
|
long id = symbolTable.getDynamicSymbolID(ref.getToAddress());
|
||||||
symProvider.symbolRemoved(id);
|
removedSymbol = symbolTable.createSymbolPlaceholder(toAddr, id);
|
||||||
|
symProvider.symbolRemoved(removedSymbol);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
refProvider.symbolChanged(symbol);
|
refProvider.symbolChanged(symbol);
|
||||||
|
@ -298,7 +300,7 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||||
|
|
||||||
case ChangeManager.DOCR_EXTERNAL_ENTRY_POINT_ADDED:
|
case ChangeManager.DOCR_EXTERNAL_ENTRY_POINT_ADDED:
|
||||||
case ChangeManager.DOCR_EXTERNAL_ENTRY_POINT_REMOVED:
|
case ChangeManager.DOCR_EXTERNAL_ENTRY_POINT_REMOVED:
|
||||||
Symbol[] symbols = currentProgram.getSymbolTable().getSymbols(rec.getStart());
|
Symbol[] symbols = symbolTable.getSymbols(rec.getStart());
|
||||||
for (Symbol element : symbols) {
|
for (Symbol element : symbols) {
|
||||||
symProvider.symbolChanged(element);
|
symProvider.symbolChanged(element);
|
||||||
refProvider.symbolChanged(element);
|
refProvider.symbolChanged(element);
|
||||||
|
|
|
@ -47,7 +47,8 @@ import ghidra.util.exception.AssertException;
|
||||||
import ghidra.util.exception.RollbackException;
|
import ghidra.util.exception.RollbackException;
|
||||||
import junit.framework.AssertionFailedError;
|
import junit.framework.AssertionFailedError;
|
||||||
import utility.application.ApplicationLayout;
|
import utility.application.ApplicationLayout;
|
||||||
import utility.function.*;
|
import utility.function.ExceptionalCallback;
|
||||||
|
import utility.function.ExceptionalFunction;
|
||||||
|
|
||||||
public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDockingTest {
|
public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDockingTest {
|
||||||
|
|
||||||
|
@ -107,7 +108,7 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock
|
||||||
* if found. If no language is found, an exception will be thrown.
|
* if found. If no language is found, an exception will be thrown.
|
||||||
* @param oldLanguageName old language name string
|
* @param oldLanguageName old language name string
|
||||||
* @return the language compiler and spec
|
* @return the language compiler and spec
|
||||||
* @throws LanguageNotFoundException
|
* @throws LanguageNotFoundException if the language is not found
|
||||||
*/
|
*/
|
||||||
public static LanguageCompilerSpecPair getLanguageCompilerSpecPair(String oldLanguageName)
|
public static LanguageCompilerSpecPair getLanguageCompilerSpecPair(String oldLanguageName)
|
||||||
throws LanguageNotFoundException {
|
throws LanguageNotFoundException {
|
||||||
|
@ -194,7 +195,14 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <E extends Exception> void tx(Program p, ExceptionalCallback<E> c) throws E {
|
/**
|
||||||
|
* Provides a convenient method for modifying the current program, handling the transaction
|
||||||
|
* logic.
|
||||||
|
*
|
||||||
|
* @param p the program
|
||||||
|
* @param c the code to execute
|
||||||
|
*/
|
||||||
|
public static <E extends Exception> void tx(Program p, ExceptionalCallback<E> c) {
|
||||||
int txId = p.startTransaction("Test - Function in Transaction");
|
int txId = p.startTransaction("Test - Function in Transaction");
|
||||||
boolean commit = true;
|
boolean commit = true;
|
||||||
try {
|
try {
|
||||||
|
@ -202,9 +210,9 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock
|
||||||
p.flushEvents();
|
p.flushEvents();
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
}
|
}
|
||||||
catch (RollbackException e) {
|
catch (Exception e) {
|
||||||
commit = false;
|
commit = false;
|
||||||
throw e;
|
failWithException("Exception modifying program '" + p.getName() + "'", e);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
p.endTransaction(txId, commit);
|
p.endTransaction(txId, commit);
|
||||||
|
@ -213,27 +221,14 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a convenient method for modifying the current program, handling the transaction
|
* Provides a convenient method for modifying the current program, handling the transaction
|
||||||
* logic
|
* logic. This method is calls {@link #tx(Program, ExceptionalCallback)}, but helps with
|
||||||
|
* semantics.
|
||||||
*
|
*
|
||||||
* @param program the program
|
* @param p the program
|
||||||
* @param callback the code to execute
|
* @param c the code to execute
|
||||||
*/
|
*/
|
||||||
public <E extends Exception> void modifyProgram(Program program,
|
public static <E extends Exception> void modifyProgram(Program p, ExceptionalCallback<E> c) {
|
||||||
ExceptionalConsumer<Program, E> callback) {
|
tx(p, c);
|
||||||
assertNotNull("Program cannot be null", program);
|
|
||||||
|
|
||||||
boolean commit = false;
|
|
||||||
int tx = program.startTransaction("Test");
|
|
||||||
try {
|
|
||||||
callback.accept(program);
|
|
||||||
commit = true;
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
failWithException("Exception modifying program '" + program.getName() + "'", e);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
program.endTransaction(tx, commit);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -244,7 +239,7 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock
|
||||||
* @param f the function for modifying the program and creating the desired result
|
* @param f the function for modifying the program and creating the desired result
|
||||||
* @return the result
|
* @return the result
|
||||||
*/
|
*/
|
||||||
public <R, E extends Exception> R createInProgram(Program program,
|
public <R, E extends Exception> R modifyProgram(Program program,
|
||||||
ExceptionalFunction<Program, R, E> f) {
|
ExceptionalFunction<Program, R, E> f) {
|
||||||
assertNotNull("Program cannot be null", program);
|
assertNotNull("Program cannot be null", program);
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,6 @@ import java.util.function.BiConsumer;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.event.ChangeEvent;
|
import javax.swing.event.ChangeEvent;
|
||||||
import javax.swing.table.JTableHeader;
|
|
||||||
import javax.swing.table.TableModel;
|
import javax.swing.table.TableModel;
|
||||||
|
|
||||||
import org.jdom.Element;
|
import org.jdom.Element;
|
||||||
|
@ -41,6 +40,7 @@ import docking.widgets.table.*;
|
||||||
import docking.widgets.table.threaded.ThreadedTableModel;
|
import docking.widgets.table.threaded.ThreadedTableModel;
|
||||||
import ghidra.app.cmd.label.AddLabelCmd;
|
import ghidra.app.cmd.label.AddLabelCmd;
|
||||||
import ghidra.app.cmd.label.CreateNamespacesCmd;
|
import ghidra.app.cmd.label.CreateNamespacesCmd;
|
||||||
|
import ghidra.app.cmd.refs.RemoveReferenceCmd;
|
||||||
import ghidra.app.plugin.core.clear.ClearCmd;
|
import ghidra.app.plugin.core.clear.ClearCmd;
|
||||||
import ghidra.app.plugin.core.clear.ClearOptions;
|
import ghidra.app.plugin.core.clear.ClearOptions;
|
||||||
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
|
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
|
||||||
|
@ -68,8 +68,15 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
private TestEnv env;
|
private TestEnv env;
|
||||||
private PluginTool tool;
|
private PluginTool tool;
|
||||||
private CodeBrowserPlugin browser;
|
private CodeBrowserPlugin cbPlugin;
|
||||||
private SymbolTablePlugin plugin;
|
private SymbolTablePlugin plugin;
|
||||||
|
private ProgramDB program;
|
||||||
|
private GTable symbolTable;
|
||||||
|
private SymbolTableModel symbolModel;
|
||||||
|
private GTable referenceTable;
|
||||||
|
private GhidraTableFilterPanel<Symbol> filterPanel;
|
||||||
|
private SymbolProvider provider;
|
||||||
|
|
||||||
private DockingActionIf viewSymAction;
|
private DockingActionIf viewSymAction;
|
||||||
private DockingActionIf viewRefAction;
|
private DockingActionIf viewRefAction;
|
||||||
private DockingActionIf deleteAction;
|
private DockingActionIf deleteAction;
|
||||||
|
@ -77,13 +84,6 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
private DockingActionIf setPinnedAction;
|
private DockingActionIf setPinnedAction;
|
||||||
private DockingActionIf clearPinnedAction;
|
private DockingActionIf clearPinnedAction;
|
||||||
private DockingActionIf setFilterAction;
|
private DockingActionIf setFilterAction;
|
||||||
private ProgramDB prog;
|
|
||||||
private GTable symbolTable;
|
|
||||||
private SymbolTableModel symbolModel;
|
|
||||||
private JTableHeader symbolTableHeader;
|
|
||||||
private GTable referenceTable;
|
|
||||||
private GhidraTableFilterPanel<SymbolRowObject> filterPanel;
|
|
||||||
private SymbolProvider provider;
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
|
@ -93,7 +93,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
tool = env.getTool();
|
tool = env.getTool();
|
||||||
configureTool(tool);
|
configureTool(tool);
|
||||||
|
|
||||||
browser = env.getPlugin(CodeBrowserPlugin.class);
|
cbPlugin = env.getPlugin(CodeBrowserPlugin.class);
|
||||||
plugin = env.getPlugin(SymbolTablePlugin.class);
|
plugin = env.getPlugin(SymbolTablePlugin.class);
|
||||||
provider = (SymbolProvider) getInstanceField("symProvider", plugin);
|
provider = (SymbolProvider) getInstanceField("symProvider", plugin);
|
||||||
|
|
||||||
|
@ -120,12 +120,12 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
@Test
|
@Test
|
||||||
public void testNavigation() throws Exception {
|
public void testNavigation() throws Exception {
|
||||||
openProgram("sample");
|
openProgram("sample");
|
||||||
int row = findRow("ghidra", "Global");
|
int row = findRow("ghidra");
|
||||||
|
|
||||||
TableModel model = symbolTable.getModel();
|
TableModel model = symbolTable.getModel();
|
||||||
doubleClick(symbolTable, row, SymbolTableModel.LOCATION_COL);
|
doubleClick(symbolTable, row, SymbolTableModel.LOCATION_COL);
|
||||||
ProgramLocation pl = getProgramLocation(row, SymbolTableModel.LOCATION_COL, model);
|
ProgramLocation pl = getProgramLocation(row, SymbolTableModel.LOCATION_COL, model);
|
||||||
assertEquals(pl.getAddress(), browser.getCurrentAddress());
|
assertEquals(pl.getAddress(), cbPlugin.getCurrentAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -351,7 +351,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy(symbolTable);
|
||||||
|
|
||||||
String symbolName = "ghidra";
|
String symbolName = "ghidra";
|
||||||
int row = findRow(symbolName, "Global");
|
int row = findRow(symbolName);
|
||||||
|
|
||||||
doubleClick(symbolTable, row, SymbolTableModel.LABEL_COL);
|
doubleClick(symbolTable, row, SymbolTableModel.LABEL_COL);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
@ -379,49 +379,40 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
public void testQuickLookup() throws Exception {
|
public void testQuickLookup() throws Exception {
|
||||||
openProgram("sample");
|
openProgram("sample");
|
||||||
|
|
||||||
int id = prog.startTransaction(testName.getMethodName());
|
tx(program, () -> {
|
||||||
try {
|
|
||||||
Address sample = prog.getMinAddress();
|
Address sample = program.getMinAddress();
|
||||||
SymbolTable st = prog.getSymbolTable();
|
SymbolTable st = program.getSymbolTable();
|
||||||
st.createLabel(sample.getNewAddress(0x01008100), "_", SourceType.USER_DEFINED);
|
st.createLabel(sample.getNewAddress(0x01008100), "_", SourceType.USER_DEFINED);
|
||||||
st.createLabel(sample.getNewAddress(0x01008100), "a", SourceType.USER_DEFINED);
|
st.createLabel(sample.getNewAddress(0x01008100), "a", SourceType.USER_DEFINED);
|
||||||
st.createLabel(sample.getNewAddress(0x01008200), "ab", SourceType.USER_DEFINED);
|
st.createLabel(sample.getNewAddress(0x01008200), "ab", SourceType.USER_DEFINED);
|
||||||
st.createLabel(sample.getNewAddress(0x01008300), "abc", SourceType.USER_DEFINED);
|
st.createLabel(sample.getNewAddress(0x01008300), "abc", SourceType.USER_DEFINED);
|
||||||
st.createLabel(sample.getNewAddress(0x01008400), "abc1", SourceType.USER_DEFINED);
|
st.createLabel(sample.getNewAddress(0x01008400), "abc1", SourceType.USER_DEFINED);
|
||||||
st.createLabel(sample.getNewAddress(0x01008500), "abc123", SourceType.USER_DEFINED);
|
st.createLabel(sample.getNewAddress(0x01008500), "abc123", SourceType.USER_DEFINED);
|
||||||
}
|
});
|
||||||
finally {
|
|
||||||
prog.endTransaction(id, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy(symbolTable);
|
||||||
|
|
||||||
selectRow(0);
|
selectRow(0);
|
||||||
|
|
||||||
triggerAutoLookup("a");
|
triggerAutoLookup("a");
|
||||||
waitForNotBusy(symbolTable);
|
|
||||||
assertEquals(findRow("a", "Global"), symbolTable.getSelectedRow());
|
assertEquals(findRow("a", "Global"), symbolTable.getSelectedRow());
|
||||||
Thread.sleep(GTable.KEY_TIMEOUT);
|
sleep(GTable.KEY_TIMEOUT);
|
||||||
|
|
||||||
triggerAutoLookup("ab");
|
triggerAutoLookup("ab");
|
||||||
waitForNotBusy(symbolTable);
|
|
||||||
assertEquals(findRow("ab", "Global"), symbolTable.getSelectedRow());
|
assertEquals(findRow("ab", "Global"), symbolTable.getSelectedRow());
|
||||||
Thread.sleep(GTable.KEY_TIMEOUT);
|
sleep(GTable.KEY_TIMEOUT);
|
||||||
|
|
||||||
triggerAutoLookup("abc");
|
triggerAutoLookup("abc");
|
||||||
waitForNotBusy(symbolTable);
|
|
||||||
assertEquals(findRow("abc", "Global"), symbolTable.getSelectedRow());
|
assertEquals(findRow("abc", "Global"), symbolTable.getSelectedRow());
|
||||||
Thread.sleep(GTable.KEY_TIMEOUT);
|
sleep(GTable.KEY_TIMEOUT);
|
||||||
|
|
||||||
triggerAutoLookup("abcd");
|
triggerAutoLookup("abcd");
|
||||||
waitForNotBusy(symbolTable);
|
|
||||||
assertEquals(findRow("abc1", "Global"), symbolTable.getSelectedRow());
|
assertEquals(findRow("abc1", "Global"), symbolTable.getSelectedRow());
|
||||||
Thread.sleep(GTable.KEY_TIMEOUT);
|
sleep(GTable.KEY_TIMEOUT);
|
||||||
|
|
||||||
selectRow(0);
|
selectRow(0);
|
||||||
waitForSwing();
|
|
||||||
triggerAutoLookup("abc12");
|
triggerAutoLookup("abc12");
|
||||||
waitForNotBusy(symbolTable);
|
|
||||||
assertEquals(findRow("abc123", "Global"), symbolTable.getSelectedRow());
|
assertEquals(findRow("abc123", "Global"), symbolTable.getSelectedRow());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,40 +423,40 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
int rowCount = symbolTable.getRowCount();
|
int rowCount = symbolTable.getRowCount();
|
||||||
assertTrue(!deleteAction.isEnabled());
|
assertTrue(!deleteAction.isEnabled());
|
||||||
|
|
||||||
final int row = findRow("ghidra", "Global");
|
int row = findRow("ghidra");
|
||||||
Rectangle rect = symbolTable.getCellRect(row, 0, true);
|
Rectangle rect = symbolTable.getCellRect(row, 0, true);
|
||||||
symbolTable.scrollRectToVisible(rect);
|
symbolTable.scrollRectToVisible(rect);
|
||||||
singleClick(symbolTable, row, 0);
|
singleClick(symbolTable, row, 0);
|
||||||
|
|
||||||
assertTrue(deleteAction.isEnabled());
|
assertTrue(deleteAction.isEnabled());
|
||||||
performAction(deleteAction, true);
|
performAction(deleteAction, true);
|
||||||
|
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy(symbolTable);
|
||||||
|
|
||||||
assertNull(getUniqueSymbol(prog, "ghidra"));
|
assertNull(getUniqueSymbol(program, "ghidra"));
|
||||||
Symbol myLocalSymbol = getUniqueSymbol(prog, "MyLocal");
|
Symbol myLocalSymbol = getUniqueSymbol(program, "MyLocal");
|
||||||
assertNotNull(myLocalSymbol);// MyLocal should have been promoted to global since user defined.
|
assertNotNull(myLocalSymbol);// MyLocal should have been promoted to global since user defined.
|
||||||
assertEquals(SourceType.USER_DEFINED, myLocalSymbol.getSource());
|
assertEquals(SourceType.USER_DEFINED, myLocalSymbol.getSource());
|
||||||
assertEquals(prog.getGlobalNamespace(), myLocalSymbol.getParentNamespace());
|
assertEquals(program.getGlobalNamespace(), myLocalSymbol.getParentNamespace());
|
||||||
Symbol anotherLocalSymbol = getUniqueSymbol(prog, "AnotherLocal");
|
|
||||||
|
int rowAfterDelete = findRow("ghidra");
|
||||||
|
assertEquals(-1, rowAfterDelete);
|
||||||
|
|
||||||
|
Symbol anotherLocalSymbol = getUniqueSymbol(program, "AnotherLocal");
|
||||||
assertNotNull(anotherLocalSymbol);// AnotherLocal should have been promoted to global since user defined.
|
assertNotNull(anotherLocalSymbol);// AnotherLocal should have been promoted to global since user defined.
|
||||||
assertEquals(SourceType.USER_DEFINED, anotherLocalSymbol.getSource());
|
assertEquals(SourceType.USER_DEFINED, anotherLocalSymbol.getSource());
|
||||||
assertEquals(prog.getGlobalNamespace(), anotherLocalSymbol.getParentNamespace());
|
assertEquals(program.getGlobalNamespace(), anotherLocalSymbol.getParentNamespace());
|
||||||
|
|
||||||
// 1 Function label removed (1 dynamic added at function entry)
|
// 1 Function label removed (1 dynamic added at function entry)
|
||||||
// Locals were promoted to global.
|
// Locals were promoted to global.
|
||||||
assertEquals(rowCount, symbolTable.getRowCount());
|
assertEquals(rowCount, symbolTable.getRowCount());
|
||||||
|
int newDynamicSymbolRow = findRow("SUB_00000052");
|
||||||
|
assertFalse(newDynamicSymbolRow == -1);
|
||||||
|
|
||||||
final int anotherLocal_RowIndex = findRow("AnotherLocal", "Global");
|
int anotherLocal_RowIndex = findRow("AnotherLocal");
|
||||||
selectRow(anotherLocal_RowIndex);
|
selectRow(anotherLocal_RowIndex);
|
||||||
|
|
||||||
int selectedRow = symbolTable.getSelectedRow();
|
|
||||||
assertEquals("Row was not selected!", anotherLocal_RowIndex, selectedRow);
|
|
||||||
|
|
||||||
waitForSwing();
|
|
||||||
|
|
||||||
performAction(deleteAction, true);
|
performAction(deleteAction, true);
|
||||||
anotherLocalSymbol = getUniqueSymbol(prog, "AnotherLocal");
|
anotherLocalSymbol = getUniqueSymbol(program, "AnotherLocal");
|
||||||
assertNull("Delete action did not delete symbol: " + anotherLocalSymbol,
|
assertNull("Delete action did not delete symbol: " + anotherLocalSymbol,
|
||||||
anotherLocalSymbol);// AnotherLocal should have been promoted to global since user defined.
|
anotherLocalSymbol);// AnotherLocal should have been promoted to global since user defined.
|
||||||
|
|
||||||
|
@ -484,10 +475,10 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
Address addr = addr("0x100");
|
Address addr = addr("0x100");
|
||||||
|
|
||||||
// grab the test symbol from the symbol table database and make sure it exists
|
// grab the test symbol from the symbol table database and make sure it exists
|
||||||
FunctionManager functionManager = prog.getFunctionManager();
|
FunctionManager functionManager = program.getFunctionManager();
|
||||||
|
|
||||||
Function function = functionManager.getFunctionContaining(addr);
|
Function function = functionManager.getFunctionContaining(addr);
|
||||||
Symbol param1Symbol = getUniqueSymbol(prog, "param_1", function);
|
Symbol param1Symbol = getUniqueSymbol(program, "param_1", function);
|
||||||
|
|
||||||
assertNotNull("Could not find param_1 in function", param1Symbol);
|
assertNotNull("Could not find param_1 in function", param1Symbol);
|
||||||
|
|
||||||
|
@ -498,7 +489,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
// execute the delete action
|
// execute the delete action
|
||||||
performAction(deleteAction, true);
|
performAction(deleteAction, true);
|
||||||
Assert.assertNotEquals(param1Symbol, getUniqueSymbol(prog, "param_1", function));
|
Assert.assertNotEquals(param1Symbol, getUniqueSymbol(program, "param_1", function));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -521,9 +512,11 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
assertTrue(!makeSelectionAction.isEnabled());
|
assertTrue(!makeSelectionAction.isEnabled());
|
||||||
|
|
||||||
final int row = findRow("ghidra", "Global");
|
int row1 = findRow("ghidra");
|
||||||
|
int row2 = findRow("KERNEL32.dll_GetProcAddress");
|
||||||
|
int row3 = findRow("LAB_00000058");
|
||||||
int rowCount = 3;
|
int rowCount = 3;
|
||||||
selectRow(row, row + 2);
|
selectRows(row1, row2, row3);
|
||||||
|
|
||||||
assertTrue(makeSelectionAction.isEnabled());
|
assertTrue(makeSelectionAction.isEnabled());
|
||||||
|
|
||||||
|
@ -533,11 +526,11 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
performAction(makeSelectionAction, true);
|
performAction(makeSelectionAction, true);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
ProgramSelection sel = browser.getCurrentSelection();
|
ProgramSelection sel = cbPlugin.getCurrentSelection();
|
||||||
|
|
||||||
assertEquals(rowCount, sel.getNumAddressRanges());
|
assertEquals(rowCount, sel.getNumAddressRanges());
|
||||||
|
|
||||||
Address sample = prog.getMinAddress();
|
Address sample = program.getMinAddress();
|
||||||
|
|
||||||
long address = 0x52;
|
long address = 0x52;
|
||||||
assertTrue("Selection does not contain address: " + address + " - selection: " + sel,
|
assertTrue("Selection does not contain address: " + address + " - selection: " + sel,
|
||||||
|
@ -555,21 +548,23 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
public void testSetAndClearPinnedAction() throws Exception {
|
public void testSetAndClearPinnedAction() throws Exception {
|
||||||
openProgram("sample");
|
openProgram("sample");
|
||||||
|
|
||||||
int row = findRow("ADVAPI32.dll_IsTextUnicode", "Global");
|
int row1 = findRow("ADVAPI32.dll_IsTextUnicode");
|
||||||
selectRow(row, row + 2);
|
int row2 = findRow("AnotherLocal", "ghidra");
|
||||||
|
int row3 = findRow("CharLowerW");
|
||||||
|
selectRows(row1, row2, row3);
|
||||||
|
|
||||||
ActionContext actionContext = provider.getActionContext(null);
|
ActionContext actionContext = provider.getActionContext(null);
|
||||||
int[] selectedRows = symbolTable.getSelectedRows();
|
int[] selectedRows = symbolTable.getSelectedRows();
|
||||||
assertEquals(3, selectedRows.length);
|
assertEquals(3, selectedRows.length);
|
||||||
for (int selectedRow : selectedRows) {
|
for (int selectedRow : selectedRows) {
|
||||||
Symbol symbol = getSymbol(selectedRow);
|
Symbol symbol = getSymbol(selectedRow);
|
||||||
assertTrue(!symbol.isPinned());
|
assertFalse(symbol.isPinned());
|
||||||
}
|
}
|
||||||
assertTrue(setPinnedAction.isEnabledForContext(actionContext));
|
assertTrue(setPinnedAction.isEnabledForContext(actionContext));
|
||||||
assertTrue(!clearPinnedAction.isEnabledForContext(actionContext));
|
assertFalse(clearPinnedAction.isEnabledForContext(actionContext));
|
||||||
|
|
||||||
performAction(setPinnedAction, actionContext, true);
|
performAction(setPinnedAction, actionContext, true);
|
||||||
waitForSwing();
|
waitForNotBusy(symbolTable);
|
||||||
for (int selectedRow : selectedRows) {
|
for (int selectedRow : selectedRows) {
|
||||||
Symbol symbol = getSymbol(selectedRow);
|
Symbol symbol = getSymbol(selectedRow);
|
||||||
assertTrue(symbol.isPinned());
|
assertTrue(symbol.isPinned());
|
||||||
|
@ -579,17 +574,17 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
for (int selectedRow : selectedRows) {
|
for (int selectedRow : selectedRows) {
|
||||||
Symbol symbol = getSymbol(selectedRow);
|
Symbol symbol = getSymbol(selectedRow);
|
||||||
assertTrue(!symbol.isPinned());
|
assertFalse(symbol.isPinned());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetPinnedActionNotEnabledForExternalSymbols() throws Exception {
|
public void testSetPinnedActionNotEnabledForExternalSymbols() throws Exception {
|
||||||
openProgram("sample");
|
openProgram("sample");
|
||||||
|
|
||||||
int row = findRow("CharLowerW", "USER32.dll");
|
int row1 = findRow("CharLowerW", "USER32.dll");
|
||||||
selectRow(row, row + 1);
|
int row2 = findRow("CharLowerZ", "USER32.dll");
|
||||||
|
selectRows(row1, row2);
|
||||||
|
|
||||||
ActionContext actionContext = provider.getActionContext(null);
|
ActionContext actionContext = provider.getActionContext(null);
|
||||||
int[] selectedRows = symbolTable.getSelectedRows();
|
int[] selectedRows = symbolTable.getSelectedRows();
|
||||||
|
@ -606,26 +601,25 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateOnSymbolsAdded() throws Exception {
|
public void testUpdateOnSymbolsAdded() throws Exception {
|
||||||
openProgram("sample");
|
openProgram("sample");
|
||||||
Address sample = prog.getMinAddress();
|
Address sample = program.getMinAddress();
|
||||||
SymbolTable st = prog.getSymbolTable();
|
SymbolTable st = program.getSymbolTable();
|
||||||
Symbol sym = null;
|
|
||||||
int rowCount = symbolTable.getRowCount();
|
int rowCount = symbolTable.getRowCount();
|
||||||
int id = prog.startTransaction(testName.getMethodName());
|
|
||||||
try {
|
Symbol sym = modifyProgram(program, p -> {
|
||||||
sym = st.createLabel(sample.getNewAddress(0x01007000), "Zeus", SourceType.USER_DEFINED);
|
return st.createLabel(sample.getNewAddress(0x01007000), "Zeus",
|
||||||
|
SourceType.USER_DEFINED);
|
||||||
|
});
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy(symbolTable);
|
||||||
assertEquals(rowCount + 1, symbolTable.getRowCount());
|
assertEquals(rowCount + 1, symbolTable.getRowCount());
|
||||||
assertTrue(symbolModel.getRowIndex(new SymbolRowObject(sym)) >= 0);
|
assertTrue(symbolModel.getRowIndex(sym) >= 0);
|
||||||
|
|
||||||
sym =
|
sym = modifyProgram(program, p -> {
|
||||||
st.createLabel(sample.getNewAddress(0x01007100), "Athena", SourceType.USER_DEFINED);
|
return st.createLabel(sample.getNewAddress(0x01007100), "Athena",
|
||||||
|
SourceType.USER_DEFINED);
|
||||||
|
});
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy(symbolTable);
|
||||||
assertEquals(rowCount + 2, symbolTable.getRowCount());
|
assertEquals(rowCount + 2, symbolTable.getRowCount());
|
||||||
assertTrue(symbolModel.getRowIndex(new SymbolRowObject(sym)) >= 0);
|
assertTrue(symbolModel.getRowIndex(sym) >= 0);
|
||||||
}
|
|
||||||
finally {
|
|
||||||
prog.endTransaction(id, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -646,22 +640,17 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
myTypeText(textField, "s");
|
myTypeText(textField, "s");
|
||||||
int rowCount = symbolModel.getRowCount();
|
int rowCount = symbolModel.getRowCount();
|
||||||
|
|
||||||
Address sample = prog.getMinAddress();
|
Address sample = program.getMinAddress();
|
||||||
SymbolTable st = prog.getSymbolTable();
|
SymbolTable st = program.getSymbolTable();
|
||||||
Symbol sym = null;
|
Symbol sym = modifyProgram(program, p -> {
|
||||||
int id = prog.startTransaction(testName.getMethodName());
|
return st.createLabel(sample.getNewAddress(0x01007000), "saaaa",
|
||||||
try {
|
SourceType.USER_DEFINED);
|
||||||
sym =
|
});
|
||||||
st.createLabel(sample.getNewAddress(0x01007000), "saaaa", SourceType.USER_DEFINED);
|
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy(symbolTable);
|
||||||
assertTrue(symbolModel.getRowIndex(new SymbolRowObject(sym)) >= 0);
|
assertTrue(symbolModel.getRowIndex(sym) >= 0);
|
||||||
}
|
|
||||||
finally {
|
|
||||||
prog.endTransaction(id, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
waitForNotBusy(symbolTable);
|
// make sure we added one while the filter is on
|
||||||
assertEquals(rowCount + 1, symbolModel.getRowCount());// make sure we added one while the filter is on
|
assertEquals(rowCount + 1, symbolModel.getRowCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -688,64 +677,53 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
//
|
//
|
||||||
assertEquals(22, symbolTable.getRowCount());
|
assertEquals(22, symbolTable.getRowCount());
|
||||||
|
|
||||||
Symbol symbol = getUniqueSymbol(prog, "ghidra");
|
Symbol symbol = getUniqueSymbol(program, "ghidra");
|
||||||
setName(symbol, null, SourceType.DEFAULT);
|
setName(symbol, null, SourceType.DEFAULT);
|
||||||
assertEquals(21, symbolTable.getRowCount());
|
assertEquals(21, symbolTable.getRowCount());
|
||||||
|
|
||||||
setName(symbol, "foobar", SourceType.USER_DEFINED);
|
setName(symbol, "foobar", SourceType.USER_DEFINED);
|
||||||
assertEquals(22, symbolTable.getRowCount());
|
assertEquals(22, symbolTable.getRowCount());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateOnSymbolsRemoved() throws Exception {
|
public void testUpdateOnSymbolsRemoved() throws Exception {
|
||||||
openProgram("sample");
|
openProgram("sample");
|
||||||
|
|
||||||
SymbolTable st = prog.getSymbolTable();
|
SymbolTable st = program.getSymbolTable();
|
||||||
Symbol sym = getUniqueSymbol(prog, "entry");
|
Symbol sym = getUniqueSymbol(program, "entry");
|
||||||
assertNull(getUniqueSymbol(prog, "EXT_00000051"));
|
assertNull(getUniqueSymbol(program, "EXT_00000051"));
|
||||||
|
|
||||||
int id = prog.startTransaction(testName.getMethodName());
|
tx(program, () -> st.removeSymbolSpecial(sym));
|
||||||
try {
|
|
||||||
st.removeSymbolSpecial(sym);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
prog.endTransaction(id, true);
|
|
||||||
}
|
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy(symbolTable);
|
||||||
|
|
||||||
// entry symbol replaced by dynamic External Entry symbol
|
// entry symbol replaced by dynamic External Entry symbol
|
||||||
assertNull(getUniqueSymbol(prog, "entry"));
|
assertNull(getUniqueSymbol(program, "entry"));
|
||||||
assertNotNull(getUniqueSymbol(prog, "EXT_00000051"));
|
assertNotNull(getUniqueSymbol(program, "EXT_00000051"));
|
||||||
assertTrue("Deleted symbol not removed from table",
|
assertTrue("Deleted symbol not removed from table", symbolModel.getRowIndex(sym) < 0);
|
||||||
symbolModel.getRowIndex(new SymbolRowObject(sym)) < 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateOnReferencesAdded() throws Exception {
|
public void testUpdateOnReferencesAdded() throws Exception {
|
||||||
openProgram("sample");
|
openProgram("sample");
|
||||||
Address sample = prog.getMinAddress();
|
Address sample = program.getMinAddress();
|
||||||
|
|
||||||
Symbol s = getUniqueSymbol(prog, "entry");
|
Symbol s = getUniqueSymbol(program, "entry");
|
||||||
|
|
||||||
int row = symbolModel.getRowIndex(new SymbolRowObject(s));
|
int row = symbolModel.getRowIndex(s);
|
||||||
Integer refCount = getRefCount(row);
|
Integer refCount = getRefCount(row);
|
||||||
assertNotNull(refCount);
|
assertNotNull(refCount);
|
||||||
assertEquals(3, refCount.intValue());
|
assertEquals(3, refCount.intValue());
|
||||||
|
|
||||||
ReferenceManager rm = prog.getReferenceManager();
|
tx(program, () -> {
|
||||||
int id = prog.startTransaction(testName.getMethodName());
|
ReferenceManager rm = program.getReferenceManager();
|
||||||
try {
|
|
||||||
Reference ref = rm.addMemoryReference(sample.getNewAddress(0x01004203),
|
Reference ref = rm.addMemoryReference(sample.getNewAddress(0x01004203),
|
||||||
sample.getNewAddress(0x51), RefType.UNCONDITIONAL_CALL, SourceType.USER_DEFINED, 0);
|
sample.getNewAddress(0x51), RefType.UNCONDITIONAL_CALL, SourceType.USER_DEFINED, 0);
|
||||||
rm.setPrimary(ref, true);
|
rm.setPrimary(ref, true);
|
||||||
}
|
});
|
||||||
finally {
|
|
||||||
prog.endTransaction(id, true);
|
|
||||||
}
|
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy(symbolTable);
|
||||||
|
|
||||||
row = symbolModel.getRowIndex(new SymbolRowObject(s));
|
row = symbolModel.getRowIndex(s);
|
||||||
|
|
||||||
refCount = getRefCount(row);
|
refCount = getRefCount(row);
|
||||||
assertNotNull(refCount);
|
assertNotNull(refCount);
|
||||||
|
@ -755,36 +733,23 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateOnReferencesRemoved() throws Exception {
|
public void testUpdateOnReferencesRemoved() throws Exception {
|
||||||
openProgram("sample");
|
openProgram("sample");
|
||||||
Address sample = prog.getMinAddress();
|
Address sample = program.getMinAddress();
|
||||||
|
|
||||||
Symbol s = getUniqueSymbol(prog, "doStuff");
|
|
||||||
|
|
||||||
int row = symbolModel.getRowIndex(new SymbolRowObject(s));
|
|
||||||
|
|
||||||
|
Symbol s = getUniqueSymbol(program, "doStuff");
|
||||||
|
int row = symbolModel.getRowIndex(s);
|
||||||
Integer refCount = getRefCount(row);
|
Integer refCount = getRefCount(row);
|
||||||
assertNotNull(refCount);
|
assertNotNull(refCount);
|
||||||
assertEquals(4, refCount.intValue());
|
assertEquals(4, refCount.intValue());
|
||||||
|
|
||||||
ReferenceManager rm = prog.getReferenceManager();
|
Address from = sample.getNewAddress(0x01004aea);
|
||||||
Reference[] refs = rm.getReferencesFrom(sample.getNewAddress(0x01004aea));
|
Address to = sample.getNewAddress(0x50);
|
||||||
Address toAddr = sample.getNewAddress(0x50);
|
Reference ref = getReference(from, to);
|
||||||
Reference ref = null;
|
|
||||||
for (Reference element : refs) {
|
tx(program, () -> {
|
||||||
if (toAddr.equals(element.getToAddress())) {
|
ReferenceManager manager = program.getReferenceManager();
|
||||||
ref = element;
|
manager.delete(ref);
|
||||||
break;
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ref == null) {
|
|
||||||
Assert.fail("Did not find expected mem reference!");
|
|
||||||
}
|
|
||||||
int id = prog.startTransaction(testName.getMethodName());
|
|
||||||
try {
|
|
||||||
rm.delete(ref);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
prog.endTransaction(id, true);
|
|
||||||
}
|
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy(symbolTable);
|
||||||
|
|
||||||
refCount = getRefCount(row);
|
refCount = getRefCount(row);
|
||||||
|
@ -792,34 +757,44 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
assertEquals(3, refCount.intValue());
|
assertEquals(3, refCount.intValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Reference getReference(Address from, Address to) {
|
||||||
|
|
||||||
|
ReferenceManager rm = program.getReferenceManager();
|
||||||
|
Reference[] refs = rm.getReferencesFrom(from);
|
||||||
|
for (Reference element : refs) {
|
||||||
|
if (to.equals(element.getToAddress())) {
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fail("Did not find expected mem reference between " + from + " and " + to);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateOnProgramRestore() throws Exception {
|
public void testUpdateOnProgramRestore() throws Exception {
|
||||||
openProgram("sample");
|
openProgram("sample");
|
||||||
|
|
||||||
int id = prog.startTransaction(testName.getMethodName());
|
int startRowCount = symbolTable.getRowCount();
|
||||||
try {
|
|
||||||
ClearCmd cmd = new ClearCmd(prog.getMemory(), new ClearOptions());
|
ClearCmd cmd = new ClearCmd(program.getMemory(), new ClearOptions());
|
||||||
tool.execute(cmd, prog);
|
applyCmd(program, cmd);
|
||||||
waitForBusyTool(tool);
|
waitForBusyTool(tool);
|
||||||
}
|
|
||||||
finally {
|
|
||||||
prog.endTransaction(id, true);
|
|
||||||
}
|
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy(symbolTable);
|
||||||
|
|
||||||
// Externals are not cleared
|
// Externals are not cleared
|
||||||
|
int clearedRowCount = 3;
|
||||||
|
assertEquals(clearedRowCount, symbolTable.getRowCount());
|
||||||
|
|
||||||
assertEquals(3, symbolTable.getRowCount());
|
undo(program);
|
||||||
|
|
||||||
undo(prog);
|
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy(symbolTable);
|
||||||
|
|
||||||
assertEquals(24, symbolTable.getRowCount());
|
assertEquals(startRowCount, symbolTable.getRowCount());
|
||||||
|
|
||||||
redo(prog);
|
redo(program);
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy(symbolTable);
|
||||||
|
|
||||||
assertEquals(3, symbolTable.getRowCount());
|
assertEquals(clearedRowCount, symbolTable.getRowCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -827,14 +802,13 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
openProgram("winword.exe");
|
openProgram("winword.exe");
|
||||||
showFilterDialog();
|
showFilterDialog();
|
||||||
|
|
||||||
final FilterDialog filterDialog = waitForDialogComponent(FilterDialog.class);
|
FilterDialog filterDialog = waitForDialogComponent(FilterDialog.class);
|
||||||
assertNotNull(filterDialog);
|
assertNotNull(filterDialog);
|
||||||
runSwing(() -> {
|
runSwing(() -> {
|
||||||
final NewSymbolFilter filter = new NewSymbolFilter();
|
NewSymbolFilter filter = new NewSymbolFilter();
|
||||||
turnOffAllFilterTypes(filter);
|
turnOffAllFilterTypes(filter);
|
||||||
filter.setFilter("Function Labels", true);
|
filter.setFilter("Function Labels", true);
|
||||||
filterDialog.setFilter(filter);
|
filterDialog.setFilter(filter);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
pressButtonByText(filterDialog, "OK");
|
pressButtonByText(filterDialog, "OK");
|
||||||
|
@ -1104,7 +1078,6 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
JTextField textField = getFilterTextField();
|
JTextField textField = getFilterTextField();
|
||||||
|
|
||||||
// setup labels in the program for matching
|
// setup labels in the program for matching
|
||||||
waitForNotBusy(symbolTable);
|
|
||||||
int rowCount = symbolTable.getRowCount();
|
int rowCount = symbolTable.getRowCount();
|
||||||
|
|
||||||
addLabel("bob", null, addr("010058f6"));
|
addLabel("bob", null, addr("010058f6"));
|
||||||
|
@ -1142,10 +1115,32 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
modelMatchesIgnoringCase("bob");
|
modelMatchesIgnoringCase("bob");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReferenceRemvoed_ReferenceToDynamicSymbol() throws Exception {
|
||||||
|
|
||||||
|
openProgram("sample");
|
||||||
|
|
||||||
|
int row = findRow("DAT_00000006");
|
||||||
|
assertTrue(row > -1);
|
||||||
|
|
||||||
|
removeReference("0x00000005", "0x00000006");
|
||||||
|
|
||||||
|
row = findRow("DAT_00000006");
|
||||||
|
assertFalse(row > -1);
|
||||||
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// Helper methods
|
// Helper methods
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
|
private void removeReference(String from, String to) {
|
||||||
|
|
||||||
|
ReferenceManager rm = program.getReferenceManager();
|
||||||
|
Reference ref = rm.getReference(addr(from), addr(to), 0);
|
||||||
|
RemoveReferenceCmd cmd = new RemoveReferenceCmd(ref);
|
||||||
|
applyCmd(program, cmd);
|
||||||
|
}
|
||||||
|
|
||||||
private void assertMenuContains(List<JMenuItem> popupItems, String string) {
|
private void assertMenuContains(List<JMenuItem> popupItems, String string) {
|
||||||
for (JMenuItem item : popupItems) {
|
for (JMenuItem item : popupItems) {
|
||||||
String text = item.getText();
|
String text = item.getText();
|
||||||
|
@ -1176,15 +1171,28 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void selectRow(int row) {
|
private void selectRow(int row) {
|
||||||
selectRow(row, row);
|
selectRows(row, row);
|
||||||
|
|
||||||
|
int selectedRow = symbolTable.getSelectedRow();
|
||||||
|
assertEquals("Row was not selected!", row, selectedRow);
|
||||||
|
waitForSwing();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void selectRow(int start, int end) {
|
private void selectRows(int... rows) {
|
||||||
|
assertNotNull(rows);
|
||||||
|
assertTrue("Must have at least one row to select", rows.length > 0);
|
||||||
runSwing(() -> {
|
runSwing(() -> {
|
||||||
symbolTable.setRowSelectionInterval(start, end);
|
|
||||||
|
symbolTable.clearSelection();
|
||||||
|
|
||||||
|
for (int row : rows) {
|
||||||
|
symbolTable.addRowSelectionInterval(row, row);
|
||||||
|
}
|
||||||
|
int end = rows[rows.length - 1];
|
||||||
Rectangle rect = symbolTable.getCellRect(end, 0, true);
|
Rectangle rect = symbolTable.getCellRect(end, 0, true);
|
||||||
symbolTable.scrollRectToVisible(rect);
|
symbolTable.scrollRectToVisible(rect);
|
||||||
});
|
});
|
||||||
|
waitForSwing();
|
||||||
}
|
}
|
||||||
|
|
||||||
private FilterDialog showFilterDialog() {
|
private FilterDialog showFilterDialog() {
|
||||||
|
@ -1226,7 +1234,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
filter.setFilter("Non-Primary Labels", active);
|
filter.setFilter("Non-Primary Labels", active);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void triggerAutoLookup(String text) {
|
private void triggerAutoLookup(String text) throws Exception {
|
||||||
|
|
||||||
KeyListener listener = (KeyListener) getInstanceField("autoLookupListener", symbolTable);
|
KeyListener listener = (KeyListener) getInstanceField("autoLookupListener", symbolTable);
|
||||||
|
|
||||||
|
@ -1240,24 +1248,16 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
// use the version of triggerText that allows us to consume the event directly, bypassing
|
// use the version of triggerText that allows us to consume the event directly, bypassing
|
||||||
// the focus system
|
// the focus system
|
||||||
triggerText(symbolTable, text, consumer);
|
triggerText(symbolTable, text, consumer);
|
||||||
|
waitForNotBusy(symbolTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setName(Symbol symbol, String name, SourceType type) throws Exception {
|
private void setName(Symbol symbol, String name, SourceType type) throws Exception {
|
||||||
int startTransaction = prog.startTransaction("Test");
|
tx(program, () -> symbol.setName(name, SourceType.DEFAULT));
|
||||||
try {
|
|
||||||
symbol.setName(name, SourceType.DEFAULT);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
prog.endTransaction(startTransaction, true);
|
|
||||||
}
|
|
||||||
waitForSwing();
|
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy(symbolTable);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Symbol getSymbol(int row) {
|
private Symbol getSymbol(int row) {
|
||||||
SymbolRowObject rowObject = symbolModel.getRowObject(row);
|
return symbolModel.getRowObject(row);
|
||||||
return rowObject.getSymbol();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Integer getRefCount(int row) {
|
private Integer getRefCount(int row) {
|
||||||
|
@ -1366,30 +1366,6 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// private void createFunctionWithDefaultParameters(Address addr) {
|
|
||||||
// CreateFunctionCmd cmd =
|
|
||||||
// new CreateFunctionCmd(null, addr, null, SourceType.DEFAULT, false, true);
|
|
||||||
// int transactionID = prog.startTransaction("TestCreateFunction");
|
|
||||||
// try {
|
|
||||||
// boolean success = tool.execute(cmd, prog);
|
|
||||||
//// boolean success = cmd.applyTo(prog);
|
|
||||||
// if (!success) {
|
|
||||||
// Assert.fail("Unexpectedly could not create a function");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// finally {
|
|
||||||
// prog.endTransaction(transactionID, true);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// prog.flushEvents();
|
|
||||||
// waitForBusyTool(tool);
|
|
||||||
//
|
|
||||||
// FunctionManager functionManager = prog.getFunctionManager();
|
|
||||||
// Function function = functionManager.getFunctionAt(addr);
|
|
||||||
// assertNotNull(function);
|
|
||||||
// }
|
|
||||||
|
|
||||||
private ProgramLocation getProgramLocation(int row, int column, TableModel model) {
|
private ProgramLocation getProgramLocation(int row, int column, TableModel model) {
|
||||||
ProgramTableModel programModel = (ProgramTableModel) model;
|
ProgramTableModel programModel = (ProgramTableModel) model;
|
||||||
return programModel.getProgramLocation(row, column);
|
return programModel.getProgramLocation(row, column);
|
||||||
|
@ -1399,9 +1375,9 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
Namespace namespace = null;
|
Namespace namespace = null;
|
||||||
if (namespaceName != null) {
|
if (namespaceName != null) {
|
||||||
Command command = new CreateNamespacesCmd(namespaceName, SourceType.USER_DEFINED);
|
Command command = new CreateNamespacesCmd(namespaceName, SourceType.USER_DEFINED);
|
||||||
if (tool.execute(command, prog)) {
|
if (tool.execute(command, program)) {
|
||||||
List<Namespace> namespaces =
|
List<Namespace> namespaces =
|
||||||
NamespaceUtils.getNamespaces(namespaceName, null, prog);
|
NamespaceUtils.getNamespaces(namespaceName, null, program);
|
||||||
|
|
||||||
if (namespaces.size() != 1) {
|
if (namespaces.size() != 1) {
|
||||||
Assert.fail("Unable to find the newly created parent namespace.");
|
Assert.fail("Unable to find the newly created parent namespace.");
|
||||||
|
@ -1411,12 +1387,12 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
Command command = new AddLabelCmd(address, label, namespace, SourceType.USER_DEFINED);
|
Command command = new AddLabelCmd(address, label, namespace, SourceType.USER_DEFINED);
|
||||||
tool.execute(command, prog);
|
tool.execute(command, program);
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy(symbolTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Address addr(String address) {
|
private Address addr(String address) {
|
||||||
return prog.getAddressFactory().getAddress(address);
|
return program.getAddressFactory().getAddress(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void myTypeText(Component c, String text) throws Exception {
|
private void myTypeText(Component c, String text) throws Exception {
|
||||||
|
@ -1482,7 +1458,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void waitForNotBusy(GTable table) throws Exception {
|
private void waitForNotBusy(GTable table) throws Exception {
|
||||||
waitForProgram(prog);
|
waitForProgram(program);
|
||||||
ThreadedTableModel<?, ?> model = (ThreadedTableModel<?, ?>) table.getModel();
|
ThreadedTableModel<?, ?> model = (ThreadedTableModel<?, ?>) table.getModel();
|
||||||
waitForTableModel(model);
|
waitForTableModel(model);
|
||||||
}
|
}
|
||||||
|
@ -1490,7 +1466,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
private void openProgram(String name) throws Exception {
|
private void openProgram(String name) throws Exception {
|
||||||
|
|
||||||
ToyProgramBuilder builder = new ToyProgramBuilder(name, true);
|
ToyProgramBuilder builder = new ToyProgramBuilder(name, true);
|
||||||
prog = builder.getProgram();
|
program = builder.getProgram();
|
||||||
|
|
||||||
builder.createMemory("test0", "1", 0x100);
|
builder.createMemory("test0", "1", 0x100);
|
||||||
builder.createMemory("test1", "0x01001000", 0x1000);
|
builder.createMemory("test1", "0x01001000", 0x1000);
|
||||||
|
@ -1543,7 +1519,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
builder.createLabel("0x80", "_SUB_010059A3");
|
builder.createLabel("0x80", "_SUB_010059A3");
|
||||||
|
|
||||||
// a generic function with params for testing
|
// a generic function with params for testing
|
||||||
ParameterImpl p = new ParameterImpl(null, new ByteDataType(), prog);
|
ParameterImpl p = new ParameterImpl(null, new ByteDataType(), program);
|
||||||
builder.createEmptyFunction("func_with_parms", "0x100", 10, new Undefined1DataType(), p, p);
|
builder.createEmptyFunction("func_with_parms", "0x100", 10, new Undefined1DataType(), p, p);
|
||||||
|
|
||||||
// references to these symbols
|
// references to these symbols
|
||||||
|
@ -1567,11 +1543,12 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
// data from ghidra
|
// data from ghidra
|
||||||
builder.createMemoryReadReference(add(ghidra, 4), add(ghidra, 6));
|
builder.createMemoryReadReference(add(ghidra, 4), add(ghidra, 6));
|
||||||
builder.createMemoryReadReference(add(ghidra, 5), add(ghidra, 7));
|
builder.createMemoryReadReference(add(ghidra, 5), add(ghidra, 7));
|
||||||
|
builder.createMemoryReadReference("0x00000005", "0x00000006");
|
||||||
|
|
||||||
// for testing navigation
|
// for testing navigation
|
||||||
builder.addBytesNOP(doStuff, 1);
|
builder.addBytesNOP(doStuff, 1);
|
||||||
|
|
||||||
env.showTool(prog);
|
env.showTool(program);
|
||||||
|
|
||||||
setUpSymbolTable();
|
setUpSymbolTable();
|
||||||
}
|
}
|
||||||
|
@ -1608,8 +1585,6 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy(symbolTable);
|
||||||
|
|
||||||
symbolTableHeader = symbolTable.getTableHeader();
|
|
||||||
|
|
||||||
sortAscending(SymbolTableModel.LABEL_COL);
|
sortAscending(SymbolTableModel.LABEL_COL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1623,11 +1598,10 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private GhidraTableFilterPanel<SymbolRowObject> getFilterPanel() {
|
private GhidraTableFilterPanel<Symbol> getFilterPanel() {
|
||||||
Object symProvider = getInstanceField("symProvider", plugin);
|
Object symProvider = getInstanceField("symProvider", plugin);
|
||||||
Object panel = getInstanceField("symbolPanel", symProvider);
|
Object panel = getInstanceField("symbolPanel", symProvider);
|
||||||
return (GhidraTableFilterPanel<SymbolRowObject>) getInstanceField("tableFilterPanel",
|
return (GhidraTableFilterPanel<Symbol>) getInstanceField("tableFilterPanel", panel);
|
||||||
panel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void singleClick(final JTable table, final int row, final int col) throws Exception {
|
private void singleClick(final JTable table, final int row, final int col) throws Exception {
|
||||||
|
@ -1655,18 +1629,20 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
tool1.addPlugin(SymbolTablePlugin.class.getName());
|
tool1.addPlugin(SymbolTablePlugin.class.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int findRow(String symbolName) {
|
||||||
|
return findRow(symbolName, "Global");
|
||||||
|
}
|
||||||
|
|
||||||
private int findRow(String symbolName, String namespace) {
|
private int findRow(String symbolName, String namespace) {
|
||||||
int max = symbolTable.getRowCount();
|
int max = symbolTable.getRowCount();
|
||||||
for (int i = 0; i < max; i++) {
|
for (int i = 0; i < max; i++) {
|
||||||
SymbolTableNameValue symbolNameValue =
|
Symbol s = (Symbol) symbolTable.getValueAt(i, SymbolTableModel.LABEL_COL);
|
||||||
(SymbolTableNameValue) symbolTable.getValueAt(i, SymbolTableModel.LABEL_COL);
|
|
||||||
Symbol s = symbolNameValue.getSymbol();
|
|
||||||
if (symbolName.equals(s.getName()) &&
|
if (symbolName.equals(s.getName()) &&
|
||||||
namespace.equals(s.getParentNamespace().getName())) {
|
namespace.equals(s.getParentNamespace().getName())) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Assert.fail("Symbol cell not found: " + namespace + "::" + symbolName);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,7 @@ import java.util.*;
|
||||||
import javax.swing.event.TableModelEvent;
|
import javax.swing.event.TableModelEvent;
|
||||||
import javax.swing.table.TableModel;
|
import javax.swing.table.TableModel;
|
||||||
|
|
||||||
import docking.widgets.table.sort.DefaultColumnComparator;
|
import docking.widgets.table.sort.*;
|
||||||
import docking.widgets.table.sort.RowToColumnComparator;
|
|
||||||
import ghidra.util.Swing;
|
import ghidra.util.Swing;
|
||||||
import ghidra.util.datastruct.WeakDataStructureFactory;
|
import ghidra.util.datastruct.WeakDataStructureFactory;
|
||||||
import ghidra.util.datastruct.WeakSet;
|
import ghidra.util.datastruct.WeakSet;
|
||||||
|
@ -331,7 +330,7 @@ public abstract class AbstractSortedTableModel<T> extends AbstractGTableModel<T>
|
||||||
*/
|
*/
|
||||||
protected Comparator<T> createSortComparator(int columnIndex) {
|
protected Comparator<T> createSortComparator(int columnIndex) {
|
||||||
return new RowToColumnComparator<>(this, columnIndex, new DefaultColumnComparator(),
|
return new RowToColumnComparator<>(this, columnIndex, new DefaultColumnComparator(),
|
||||||
new StringBasedBackupRowToColumnComparator(columnIndex));
|
new StringBasedBackupRowToColumnComparator());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Comparator<T> createLastResortComparator(ComparatorLink parentChain) {
|
private Comparator<T> createLastResortComparator(ComparatorLink parentChain) {
|
||||||
|
@ -470,22 +469,16 @@ public abstract class AbstractSortedTableModel<T> extends AbstractGTableModel<T>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class StringBasedBackupRowToColumnComparator implements Comparator<T> {
|
private class StringBasedBackupRowToColumnComparator implements BackupColumnComparator<T> {
|
||||||
|
|
||||||
private int sortColumn;
|
|
||||||
|
|
||||||
StringBasedBackupRowToColumnComparator(int sortColumn) {
|
|
||||||
this.sortColumn = sortColumn;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(T t1, T t2) {
|
public int compare(T t1, T t2, Object c1, Object c2) {
|
||||||
if (t1 == t2) {
|
if (t1 == t2) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
String s1 = getColumStringValue(t1);
|
String s1 = getColumStringValue(c1);
|
||||||
String s2 = getColumStringValue(t2);
|
String s2 = getColumStringValue(c2);
|
||||||
|
|
||||||
if (s1 == null || s2 == null) {
|
if (s1 == null || s2 == null) {
|
||||||
return TableComparators.compareWithNullValues(s1, s2);
|
return TableComparators.compareWithNullValues(s1, s2);
|
||||||
|
@ -494,11 +487,10 @@ public abstract class AbstractSortedTableModel<T> extends AbstractGTableModel<T>
|
||||||
return s1.compareToIgnoreCase(s2);
|
return s1.compareToIgnoreCase(s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getColumStringValue(T t) {
|
private String getColumStringValue(Object columnValue) {
|
||||||
// just use the toString(), which may or may not produce a good value (this will
|
// just use the toString(), which may or may not produce a good value (this will
|
||||||
// catch the cases where the column value is itself a string)
|
// catch the cases where the column value is itself a string)
|
||||||
Object o = getColumnValueForRow(t, sortColumn);
|
return columnValue == null ? null : columnValue.toString();
|
||||||
return o == null ? null : o.toString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -34,6 +33,7 @@ public class AddRemoveListItem<T> {
|
||||||
public boolean isRemove() {
|
public boolean isRemove() {
|
||||||
return isRemove;
|
return isRemove;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isChange() {
|
public boolean isChange() {
|
||||||
return isAdd && isRemove;
|
return isAdd && isRemove;
|
||||||
}
|
}
|
||||||
|
@ -41,4 +41,16 @@ public class AddRemoveListItem<T> {
|
||||||
public T getValue() {
|
public T getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
return "{\n" +
|
||||||
|
"\tvalue: " + value +",\n" +
|
||||||
|
"\tisAdd: " + isAdd +",\n" +
|
||||||
|
"\tisRemove: " + isRemove +"\n" +
|
||||||
|
"}";
|
||||||
|
//@formatter:on
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -441,7 +441,6 @@ public abstract class GDynamicColumnTableModel<ROW_TYPE, DATA_SOURCE>
|
||||||
}
|
}
|
||||||
|
|
||||||
return column.getValue(t, columnSettings.get(column), dataSource, serviceProvider);
|
return column.getValue(t, columnSettings.get(column), dataSource, serviceProvider);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package docking.widgets.table.sort;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface that is conceptually the same as a {@link Comparator}. The only difference is
|
||||||
|
* that we pass the row objects <b>and</b> the column values to
|
||||||
|
* {@link #compare(Object, Object, Object, Object)}. This allows us to take advantage of
|
||||||
|
* already-retrieved column values. This can speed-up table sorting, as repeatedly retrieving
|
||||||
|
* column values for each comparison is slow.
|
||||||
|
*
|
||||||
|
* @param <T> the row type
|
||||||
|
*/
|
||||||
|
public interface BackupColumnComparator<T> {
|
||||||
|
|
||||||
|
static final BackupColumnComparator<Object> NO_SORT_COMPARATOR = (t1, t2, o1, o2) -> 0;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked") // we are casting to Object; safe since no comparisons are done
|
||||||
|
public static <T> BackupColumnComparator<T> getNoSortComparator() {
|
||||||
|
return (BackupColumnComparator<T>) NO_SORT_COMPARATOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares two row/column values using the same contract as
|
||||||
|
* {@link Comparator#compare(Object, Object)}
|
||||||
|
*
|
||||||
|
* @param t1 the 1st row object
|
||||||
|
* @param t2 the 2nd row object
|
||||||
|
* @param c1 the 1st column value
|
||||||
|
* @param c2 the second column value
|
||||||
|
* @return 0 if the 2 values compare the same; negative if the first value compares less than
|
||||||
|
* the second; positive if the first value compares as larger than the first
|
||||||
|
*/
|
||||||
|
public int compare(T t1, T t2, Object c1, Object c2);
|
||||||
|
}
|
|
@ -15,8 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package docking.widgets.table.sort;
|
package docking.widgets.table.sort;
|
||||||
|
|
||||||
import java.util.Comparator;
|
|
||||||
|
|
||||||
import docking.widgets.table.*;
|
import docking.widgets.table.*;
|
||||||
import ghidra.docking.settings.Settings;
|
import ghidra.docking.settings.Settings;
|
||||||
import ghidra.util.table.column.GColumnRenderer;
|
import ghidra.util.table.column.GColumnRenderer;
|
||||||
|
@ -29,7 +27,7 @@ import ghidra.util.table.column.GColumnRenderer.ColumnConstraintFilterMode;
|
||||||
*
|
*
|
||||||
* @param <T> the row type
|
* @param <T> the row type
|
||||||
*/
|
*/
|
||||||
public class ColumnRenderedValueBackupRowComparator<T> implements Comparator<T> {
|
public class ColumnRenderedValueBackupRowComparator<T> implements BackupColumnComparator<T> {
|
||||||
|
|
||||||
protected int sortColumn;
|
protected int sortColumn;
|
||||||
protected DynamicColumnTableModel<T> model;
|
protected DynamicColumnTableModel<T> model;
|
||||||
|
@ -56,13 +54,13 @@ public class ColumnRenderedValueBackupRowComparator<T> implements Comparator<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(T t1, T t2) {
|
public int compare(T t1, T t2, Object c1, Object c2) {
|
||||||
if (t1 == t2) {
|
if (t1 == t2) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
String s1 = getRenderedColumnStringValue(t1);
|
String s1 = getRenderedColumnStringValue(c1);
|
||||||
String s2 = getRenderedColumnStringValue(t2);
|
String s2 = getRenderedColumnStringValue(c2);
|
||||||
|
|
||||||
if (s1 == null || s2 == null) {
|
if (s1 == null || s2 == null) {
|
||||||
return TableComparators.compareWithNullValues(s1, s2);
|
return TableComparators.compareWithNullValues(s1, s2);
|
||||||
|
@ -75,7 +73,7 @@ public class ColumnRenderedValueBackupRowComparator<T> implements Comparator<T>
|
||||||
// unsafe. We happen know that we retrieved the value from the column that we are passing
|
// unsafe. We happen know that we retrieved the value from the column that we are passing
|
||||||
// it to, so the casting and usage is indeed safe.
|
// it to, so the casting and usage is indeed safe.
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private String getRenderedColumnStringValue(T t) {
|
private String getRenderedColumnStringValue(Object columnValue) {
|
||||||
|
|
||||||
if (!supportsColumnSorting) {
|
if (!supportsColumnSorting) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -83,13 +81,12 @@ public class ColumnRenderedValueBackupRowComparator<T> implements Comparator<T>
|
||||||
|
|
||||||
DynamicTableColumn<T, ?, ?> column = model.getColumn(sortColumn);
|
DynamicTableColumn<T, ?, ?> column = model.getColumn(sortColumn);
|
||||||
GColumnRenderer<Object> renderer = (GColumnRenderer<Object>) column.getColumnRenderer();
|
GColumnRenderer<Object> renderer = (GColumnRenderer<Object>) column.getColumnRenderer();
|
||||||
Object o = getColumnValue(t);
|
|
||||||
if (renderer == null) {
|
if (renderer == null) {
|
||||||
return o == null ? null : o.toString();
|
return columnValue == null ? null : columnValue.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings settings = model.getColumnSettings(sortColumn);
|
Settings settings = model.getColumnSettings(sortColumn);
|
||||||
return renderer.getFilterString(o, settings);
|
return renderer.getFilterString(columnValue, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this may be overridden to use caching
|
// this may be overridden to use caching
|
||||||
|
|
|
@ -32,7 +32,8 @@ public class RowToColumnComparator<T> implements Comparator<T> {
|
||||||
protected RowObjectTableModel<T> model;
|
protected RowObjectTableModel<T> model;
|
||||||
protected int sortColumn;
|
protected int sortColumn;
|
||||||
protected Comparator<Object> columnComparator;
|
protected Comparator<Object> columnComparator;
|
||||||
protected Comparator<T> backupRowComparator = TableComparators.getNoSortComparator();
|
protected BackupColumnComparator<T> backupRowComparator =
|
||||||
|
BackupColumnComparator.getNoSortComparator();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs this class with the given column comparator that will get called after the
|
* Constructs this class with the given column comparator that will get called after the
|
||||||
|
@ -60,7 +61,7 @@ public class RowToColumnComparator<T> implements Comparator<T> {
|
||||||
* @param backupRowComparator the backup row comparator
|
* @param backupRowComparator the backup row comparator
|
||||||
*/
|
*/
|
||||||
public RowToColumnComparator(RowObjectTableModel<T> model, int sortColumn,
|
public RowToColumnComparator(RowObjectTableModel<T> model, int sortColumn,
|
||||||
Comparator<Object> comparator, Comparator<T> backupRowComparator) {
|
Comparator<Object> comparator, BackupColumnComparator<T> backupRowComparator) {
|
||||||
this.model = model;
|
this.model = model;
|
||||||
this.sortColumn = sortColumn;
|
this.sortColumn = sortColumn;
|
||||||
this.columnComparator = Objects.requireNonNull(comparator);
|
this.columnComparator = Objects.requireNonNull(comparator);
|
||||||
|
@ -97,7 +98,7 @@ public class RowToColumnComparator<T> implements Comparator<T> {
|
||||||
// backup comparator is not a stub and will do something reasonable for the sort,
|
// backup comparator is not a stub and will do something reasonable for the sort,
|
||||||
// depending upon how the model created this class.
|
// depending upon how the model created this class.
|
||||||
//
|
//
|
||||||
return backupRowComparator.compare(t1, t2);
|
return backupRowComparator.compare(t1, t2, value1, value2);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Object getColumnValue(T t) {
|
protected Object getColumnValue(T t) {
|
||||||
|
|
|
@ -17,6 +17,7 @@ package docking.widgets.table.threaded;
|
||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
import docking.widgets.table.sort.BackupColumnComparator;
|
||||||
import docking.widgets.table.sort.RowToColumnComparator;
|
import docking.widgets.table.sort.RowToColumnComparator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -55,7 +56,7 @@ public class ThreadedTableColumnComparator<T> extends RowToColumnComparator<T> {
|
||||||
* @see RowToColumnComparator
|
* @see RowToColumnComparator
|
||||||
*/
|
*/
|
||||||
public ThreadedTableColumnComparator(ThreadedTableModel<T, ?> model, int sortColumn,
|
public ThreadedTableColumnComparator(ThreadedTableModel<T, ?> model, int sortColumn,
|
||||||
Comparator<Object> comparator, Comparator<T> backupRowComparator) {
|
Comparator<Object> comparator, BackupColumnComparator<T> backupRowComparator) {
|
||||||
super(model, sortColumn, comparator, backupRowComparator);
|
super(model, sortColumn, comparator, backupRowComparator);
|
||||||
this.threadedModel = model;
|
this.threadedModel = model;
|
||||||
}
|
}
|
||||||
|
|
|
@ -214,7 +214,37 @@ public abstract class ThreadedTableModel<ROW_OBJECT, DATA_SOURCE>
|
||||||
protected abstract void doLoad(Accumulator<ROW_OBJECT> accumulator, TaskMonitor monitor)
|
protected abstract void doLoad(Accumulator<ROW_OBJECT> accumulator, TaskMonitor monitor)
|
||||||
throws CancelledException;
|
throws CancelledException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will retrieve a column value for the given row object. Further, the retrieved
|
||||||
|
* value will be cached. This is useful when sorting a table, as the same column value may
|
||||||
|
* be requested multiple times.
|
||||||
|
*
|
||||||
|
* <p><u>Performance Notes</u>
|
||||||
|
* <ul>
|
||||||
|
* <li>This method uses a {@link HashMap} to cache column values for a row object. Further,
|
||||||
|
* upon a key collision, the map will perform O(logn) lookups <b>if the
|
||||||
|
* key (the row object) is {@link Comparable}</b>. If the key is not comparable, then
|
||||||
|
* the collision lookups will be linear. So, make your row objects comparable
|
||||||
|
* for maximum speed <b>when your table size becomes large</b> (for small tables there
|
||||||
|
* is no observable impact).
|
||||||
|
* <li>Even if your row objects are comparable, relying on this table model to convert your
|
||||||
|
* row object into column values can be slow <b>for large tables</b>. This is because
|
||||||
|
* the default column comparison framework for the tables will call this method
|
||||||
|
* multiple times, resulting in many more method calls per column value lookup. For
|
||||||
|
* large data, the repeated method calls start to become noticeable. For maximum
|
||||||
|
* column sorting speed, use a comparator that works not on the column value, but on
|
||||||
|
* the row value. To do this, return a comparator from your model's
|
||||||
|
* {@link #createSortComparator(int)} method, instead of from the column itself or
|
||||||
|
* by relying on column item implementing {@link Comparable}. This is possible any
|
||||||
|
* time that a row object already has a field that is used for a given column.
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param rowObject the row object
|
||||||
|
* @param columnIndex the column index for which to get a value
|
||||||
|
* @return the column value
|
||||||
|
*/
|
||||||
Object getCachedColumnValueForRow(ROW_OBJECT rowObject, int columnIndex) {
|
Object getCachedColumnValueForRow(ROW_OBJECT rowObject, int columnIndex) {
|
||||||
|
|
||||||
Map<ROW_OBJECT, Map<Integer, Object>> cachedColumnValues = threadLocalColumnCache.get();
|
Map<ROW_OBJECT, Map<Integer, Object>> cachedColumnValues = threadLocalColumnCache.get();
|
||||||
|
|
||||||
if (cachedColumnValues == null) {
|
if (cachedColumnValues == null) {
|
||||||
|
|
|
@ -58,7 +58,7 @@ public class TestThread extends Thread {
|
||||||
/**
|
/**
|
||||||
* Returns true if the given thread name is the test thread name
|
* Returns true if the given thread name is the test thread name
|
||||||
*
|
*
|
||||||
* @param t the thread name to check
|
* @param name the thread name to check
|
||||||
* @return true if the given thread name is the test thread name
|
* @return true if the given thread name is the test thread name
|
||||||
*/
|
*/
|
||||||
public static boolean isTestThreadName(String name) {
|
public static boolean isTestThreadName(String name) {
|
||||||
|
|
|
@ -48,7 +48,7 @@ public class LRUMap<K, V> implements Map<K, V> {
|
||||||
protected HashMap<K, Entry<K, V>> map;
|
protected HashMap<K, Entry<K, V>> map;
|
||||||
private int cacheSize;
|
private int cacheSize;
|
||||||
private Entry<K, V> head;
|
private Entry<K, V> head;
|
||||||
private long modificationID = 0;
|
private volatile long modificationID = 0;
|
||||||
|
|
||||||
public LRUMap(int cacheSize) {
|
public LRUMap(int cacheSize) {
|
||||||
this.cacheSize = cacheSize;
|
this.cacheSize = cacheSize;
|
||||||
|
@ -267,7 +267,7 @@ public class LRUMap<K, V> implements Map<K, V> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is called after an item has been removed from the cache.
|
* This is called after an item has been removed from the cache.
|
||||||
* @param eldest the ite being removed
|
* @param eldest the item being removed
|
||||||
*/
|
*/
|
||||||
protected void eldestEntryRemoved(Map.Entry<K, V> eldest) {
|
protected void eldestEntryRemoved(Map.Entry<K, V> eldest) {
|
||||||
// this is just a way for subclasses to know when items are removed from the cache
|
// this is just a way for subclasses to know when items are removed from the cache
|
||||||
|
|
|
@ -217,7 +217,8 @@ public class CodeSymbol extends SymbolDB {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean isValidParent(Namespace parent) {
|
public boolean isValidParent(Namespace parent) {
|
||||||
return SymbolType.LABEL.isValidParent(symbolMgr.getProgram(), parent, address, isExternal());
|
return SymbolType.LABEL.isValidParent(symbolMgr.getProgram(), parent, address,
|
||||||
|
isExternal());
|
||||||
|
|
||||||
// if (isExternal() != parent.isExternal()) {
|
// if (isExternal() != parent.isExternal()) {
|
||||||
// return false;
|
// return false;
|
||||||
|
@ -241,15 +242,12 @@ public class CodeSymbol extends SymbolDB {
|
||||||
// return true;
|
// return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Symbol#getName()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
protected String doGetName() {
|
||||||
if (getSource() == SourceType.DEFAULT && isExternal()) {
|
if (getSource() == SourceType.DEFAULT && isExternal()) {
|
||||||
return ExternalManagerDB.getDefaultExternalName(this);
|
return ExternalManagerDB.getDefaultExternalName(this);
|
||||||
}
|
}
|
||||||
return super.getName();
|
return super.doGetName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -33,7 +33,6 @@ import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
import ghidra.util.task.TaskMonitorAdapter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Symbol class for functions.
|
* Symbol class for functions.
|
||||||
|
@ -237,11 +236,8 @@ public class FunctionSymbol extends SymbolDB {
|
||||||
isExternal());
|
isExternal());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Symbol#getName()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
protected String doGetName() {
|
||||||
if (getSource() == SourceType.DEFAULT) {
|
if (getSource() == SourceType.DEFAULT) {
|
||||||
if (isExternal()) {
|
if (isExternal()) {
|
||||||
return ExternalManagerDB.getDefaultExternalName(this);
|
return ExternalManagerDB.getDefaultExternalName(this);
|
||||||
|
@ -251,17 +247,17 @@ public class FunctionSymbol extends SymbolDB {
|
||||||
Symbol thunkedSymbol = getThunkedSymbol();
|
Symbol thunkedSymbol = getThunkedSymbol();
|
||||||
if (thunkedSymbol instanceof FunctionSymbol) {
|
if (thunkedSymbol instanceof FunctionSymbol) {
|
||||||
FunctionSymbol thunkedFuncSym = (FunctionSymbol) thunkedSymbol;
|
FunctionSymbol thunkedFuncSym = (FunctionSymbol) thunkedSymbol;
|
||||||
String name = thunkedFuncSym.getName();
|
String thunkName = thunkedFuncSym.getName();
|
||||||
if (thunkedFuncSym.getSource() == SourceType.DEFAULT &&
|
if (thunkedFuncSym.getSource() == SourceType.DEFAULT &&
|
||||||
thunkedFuncSym.getThunkedSymbol() == null) {
|
thunkedFuncSym.getThunkedSymbol() == null) {
|
||||||
// if thunking a default non-thunk function
|
// if thunking a default non-thunk function
|
||||||
name = "thunk_" + name;
|
thunkName = "thunk_" + thunkName;
|
||||||
}
|
}
|
||||||
return name;
|
return thunkName;
|
||||||
}
|
}
|
||||||
return SymbolUtilities.getDefaultFunctionName(address);
|
return SymbolUtilities.getDefaultFunctionName(address);
|
||||||
}
|
}
|
||||||
return super.getName();
|
return super.doGetName();
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override
|
// @Override
|
||||||
|
@ -363,7 +359,7 @@ public class FunctionSymbol extends SymbolDB {
|
||||||
checkIsValid();
|
checkIsValid();
|
||||||
Reference[] refs = super.getReferences(monitor);
|
Reference[] refs = super.getReferences(monitor);
|
||||||
if (monitor == null) {
|
if (monitor == null) {
|
||||||
monitor = TaskMonitorAdapter.DUMMY_MONITOR;
|
monitor = TaskMonitor.DUMMY;
|
||||||
}
|
}
|
||||||
if (monitor.isCancelled()) {
|
if (monitor.isCancelled()) {
|
||||||
return refs;
|
return refs;
|
||||||
|
|
|
@ -54,7 +54,7 @@ public class GlobalVariableSymbolDB extends VariableSymbolDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
protected String doGetName() {
|
||||||
if (!checkIsValid()) {
|
if (!checkIsValid()) {
|
||||||
// TODO: SCR
|
// TODO: SCR
|
||||||
return "[Invalid VariableSymbol - Deleted!]";
|
return "[Invalid VariableSymbol - Deleted!]";
|
||||||
|
@ -63,7 +63,7 @@ public class GlobalVariableSymbolDB extends VariableSymbolDB {
|
||||||
if (storage == null) {
|
if (storage == null) {
|
||||||
return Function.DEFAULT_LOCAL_PREFIX + "_!BAD!";
|
return Function.DEFAULT_LOCAL_PREFIX + "_!BAD!";
|
||||||
}
|
}
|
||||||
return super.getName();
|
return super.doGetName();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,11 +30,13 @@ import ghidra.program.model.listing.CircularDependencyException;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.program.util.ChangeManager;
|
import ghidra.program.util.ChangeManager;
|
||||||
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.util.Lock;
|
import ghidra.util.Lock;
|
||||||
import ghidra.util.SystemUtilities;
|
import ghidra.util.SystemUtilities;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
import ghidra.util.task.*;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
import ghidra.util.task.UnknownProgressWrappingTaskMonitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for symbols
|
* Base class for symbols
|
||||||
|
@ -43,10 +45,25 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
|
|
||||||
private Record record;
|
private Record record;
|
||||||
private boolean isDeleting = false;
|
private boolean isDeleting = false;
|
||||||
|
protected String name;
|
||||||
protected Address address;
|
protected Address address;
|
||||||
protected SymbolManager symbolMgr;
|
protected SymbolManager symbolMgr;
|
||||||
protected Lock lock;
|
protected Lock lock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Symbol that is just a placeholder for use when trying to find symbols by using
|
||||||
|
* {@link Symbol#getID()}. This is useful for locating symbols in Java collections when
|
||||||
|
* a symbol has been deleted and the only remaining information is that symbol's ID.
|
||||||
|
*
|
||||||
|
* @param manager the manager for the new symbol
|
||||||
|
* @param address the address of the symbol
|
||||||
|
* @param id the id of the symbol
|
||||||
|
* @return the fake symbol
|
||||||
|
*/
|
||||||
|
static SymbolDB createSymbolPlaceholder(SymbolManager manager, Address address, long id) {
|
||||||
|
return new PlaceholderSymbolDB(manager, address, id);
|
||||||
|
}
|
||||||
|
|
||||||
SymbolDB(SymbolManager symbolMgr, DBObjectCache<SymbolDB> cache, Address address,
|
SymbolDB(SymbolManager symbolMgr, DBObjectCache<SymbolDB> cache, Address address,
|
||||||
Record record) {
|
Record record) {
|
||||||
super(cache, record.getKey());
|
super(cache, record.getKey());
|
||||||
|
@ -65,6 +82,11 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
// prefer cached name for speed; it may be stale; call getName() for current value
|
||||||
|
String temp = name;
|
||||||
|
if (temp != null) {
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
return getName();
|
return getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,6 +97,7 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean refresh(Record rec) {
|
protected boolean refresh(Record rec) {
|
||||||
|
name = null;
|
||||||
if (record != null) {
|
if (record != null) {
|
||||||
if (rec == null) {
|
if (rec == null) {
|
||||||
rec = symbolMgr.getSymbolRecord(key);
|
rec = symbolMgr.getSymbolRecord(key);
|
||||||
|
@ -145,17 +168,29 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
checkIsValid();
|
checkIsValid();
|
||||||
if (record != null) {
|
if (name == null) {
|
||||||
return record.getString(SymbolDatabaseAdapter.SYMBOL_NAME_COL);
|
name = doGetName();
|
||||||
}
|
}
|
||||||
|
return name;
|
||||||
return SymbolUtilities.getDynamicName(symbolMgr.getProgram(), address);
|
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
lock.release();
|
lock.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The code for creating the name content for this symbol. This code will be called
|
||||||
|
* with the symbol's lock.
|
||||||
|
*
|
||||||
|
* @return the name
|
||||||
|
*/
|
||||||
|
protected String doGetName() {
|
||||||
|
if (record != null) {
|
||||||
|
return record.getString(SymbolDatabaseAdapter.SYMBOL_NAME_COL);
|
||||||
|
}
|
||||||
|
return SymbolUtilities.getDynamicName(symbolMgr.getProgram(), address);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Program getProgram() {
|
public Program getProgram() {
|
||||||
return symbolMgr.getProgram();
|
return symbolMgr.getProgram();
|
||||||
|
@ -238,7 +273,7 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
try {
|
try {
|
||||||
checkIsValid();
|
checkIsValid();
|
||||||
if (monitor == null) {
|
if (monitor == null) {
|
||||||
monitor = TaskMonitorAdapter.DUMMY_MONITOR;
|
monitor = TaskMonitor.DUMMY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (monitor.getMaximum() == 0) {
|
if (monitor.getMaximum() == 0) {
|
||||||
|
@ -275,7 +310,7 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Reference[] getReferences() {
|
public Reference[] getReferences() {
|
||||||
return getReferences(TaskMonitorAdapter.DUMMY_MONITOR);
|
return getReferences(TaskMonitor.DUMMY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -470,7 +505,11 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allow symbol implementations to validate the source when setting the name of
|
* Allow symbol implementations to validate the source when setting the name of
|
||||||
* this symbol.
|
* this symbol
|
||||||
|
*
|
||||||
|
* @param newName the new name
|
||||||
|
* @param source the source type
|
||||||
|
* @return the validated source type
|
||||||
*/
|
*/
|
||||||
protected SourceType validateNameSource(String newName, SourceType source) {
|
protected SourceType validateNameSource(String newName, SourceType source) {
|
||||||
return source;
|
return source;
|
||||||
|
@ -482,6 +521,7 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
|
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
|
name = null;
|
||||||
checkDeleted();
|
checkDeleted();
|
||||||
checkEditOK();
|
checkEditOK();
|
||||||
|
|
||||||
|
@ -535,6 +575,7 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
|
|
||||||
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, newNamespace.getID());
|
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, newNamespace.getID());
|
||||||
record.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, newName);
|
record.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, newName);
|
||||||
|
name = newName;
|
||||||
updateSymbolSource(record, source);
|
updateSymbolSource(record, source);
|
||||||
updateRecord();
|
updateRecord();
|
||||||
|
|
||||||
|
@ -613,10 +654,16 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
if (obj == this) {
|
if (obj == this) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol s = (Symbol) obj;
|
Symbol s = (Symbol) obj;
|
||||||
|
if (getID() == s.getID()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!getName().equals(s.getName())) {
|
if (!getName().equals(s.getName())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!getAddress().equals(s.getAddress())) {
|
if (!getAddress().equals(s.getAddress())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -776,6 +823,7 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gets the generic symbol data 2 data.
|
* gets the generic symbol data 2 data.
|
||||||
|
* @return the symbol data
|
||||||
*/
|
*/
|
||||||
public int getSymbolData2() {
|
public int getSymbolData2() {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
|
@ -852,10 +900,64 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the record and key associated with this symbol
|
* Change the record and key associated with this symbol
|
||||||
* @param the record.
|
* @param record the record
|
||||||
*/
|
*/
|
||||||
void setRecord(Record record) {
|
void setRecord(Record record) {
|
||||||
this.record = record;
|
this.record = record;
|
||||||
keyChanged(record.getKey());
|
keyChanged(record.getKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class PlaceholderSymbolDB extends SymbolDB {
|
||||||
|
|
||||||
|
PlaceholderSymbolDB(SymbolManager symbolMgr, Address address, long key) {
|
||||||
|
super(symbolMgr, null, address, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if ((obj == null) || (!(obj instanceof Symbol))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (obj == this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this class is only ever equal if the id matches
|
||||||
|
Symbol s = (Symbol) obj;
|
||||||
|
if (getID() == s.getID()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SymbolType getSymbolType() {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProgramLocation getProgramLocation() {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isExternal() {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getObject() {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPrimary() {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValidParent(Namespace parent) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2274,6 +2274,11 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
return new NamespaceDB(s, namespaceMgr);
|
return new NamespaceDB(s, namespaceMgr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Symbol createSymbolPlaceholder(Address address, long id) {
|
||||||
|
return SymbolDB.createSymbolPlaceholder(this, address, id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a symbol, specifying all information for the record. This method is not on the
|
* Creates a symbol, specifying all information for the record. This method is not on the
|
||||||
* public interface and is only intended for program API internal use. The user of this
|
* public interface and is only intended for program API internal use. The user of this
|
||||||
|
@ -2675,5 +2680,4 @@ class SymbolMatcher implements Predicate<Symbol> {
|
||||||
SymbolType type = s.getSymbolType();
|
SymbolType type = s.getSymbolType();
|
||||||
return type == type1;
|
return type == type1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -203,7 +203,7 @@ public class VariableSymbolDB extends SymbolDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
protected String doGetName() {
|
||||||
if (!checkIsValid()) {
|
if (!checkIsValid()) {
|
||||||
// TODO: SCR
|
// TODO: SCR
|
||||||
return "[Invalid VariableSymbol - Deleted!]";
|
return "[Invalid VariableSymbol - Deleted!]";
|
||||||
|
@ -213,7 +213,7 @@ public class VariableSymbolDB extends SymbolDB {
|
||||||
if (getSource() == SourceType.DEFAULT) {
|
if (getSource() == SourceType.DEFAULT) {
|
||||||
return getParamName();
|
return getParamName();
|
||||||
}
|
}
|
||||||
String storedName = super.getName();
|
String storedName = super.doGetName();
|
||||||
if (SymbolUtilities.isDefaultParameterName(storedName)) {
|
if (SymbolUtilities.isDefaultParameterName(storedName)) {
|
||||||
return getParamName();
|
return getParamName();
|
||||||
}
|
}
|
||||||
|
@ -232,7 +232,7 @@ public class VariableSymbolDB extends SymbolDB {
|
||||||
// TODO: we use to check for a default name and regenerate new default name but we should
|
// TODO: we use to check for a default name and regenerate new default name but we should
|
||||||
// not need to do this if source remains at default
|
// not need to do this if source remains at default
|
||||||
|
|
||||||
return super.getName();
|
return super.doGetName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -543,4 +543,15 @@ public interface SymbolTable {
|
||||||
public Namespace createNameSpace(Namespace parent, String name, SourceType source)
|
public Namespace createNameSpace(Namespace parent, String name, SourceType source)
|
||||||
throws DuplicateNameException, InvalidInputException;
|
throws DuplicateNameException, InvalidInputException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Symbol that is just a placeholder for use when trying to find symbols by using
|
||||||
|
* {@link Symbol#getID()}. This is useful for locating symbols in Java collections when
|
||||||
|
* a symbol has been deleted and the only remaining information is that symbol's ID.
|
||||||
|
*
|
||||||
|
* @param address the address of the symbol
|
||||||
|
* @param id the id of the symbol
|
||||||
|
* @return the fake symbol
|
||||||
|
*/
|
||||||
|
public Symbol createSymbolPlaceholder(Address address, long id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -897,7 +897,11 @@ public class SymbolUtilities {
|
||||||
if (symbol.isExternal()) {
|
if (symbol.isExternal()) {
|
||||||
return "External Function";
|
return "External Function";
|
||||||
}
|
}
|
||||||
|
|
||||||
Function func = (Function) symbol.getObject();
|
Function func = (Function) symbol.getObject();
|
||||||
|
if (func == null) {
|
||||||
|
return null; // symbol deleted
|
||||||
|
}
|
||||||
if (func.isThunk()) {
|
if (func.isThunk()) {
|
||||||
return "Thunk Function";
|
return "Thunk Function";
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue