mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Merge remote-tracking branch
'origin/GP-788-dragonmacher-symbol-table-ui-lockup--SQUASHED' Conflicts: Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolTablePlugin.java
This commit is contained in:
commit
ceb0b5ad27
10 changed files with 411 additions and 123 deletions
|
@ -299,6 +299,10 @@ public class BookmarkPlugin extends ProgramPlugin
|
||||||
@Override
|
@Override
|
||||||
public synchronized void domainObjectChanged(DomainObjectChangedEvent ev) {
|
public synchronized void domainObjectChanged(DomainObjectChangedEvent ev) {
|
||||||
|
|
||||||
|
if (!provider.isVisible()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (ev.containsEvent(DomainObject.DO_OBJECT_RESTORED) ||
|
if (ev.containsEvent(DomainObject.DO_OBJECT_RESTORED) ||
|
||||||
ev.containsEvent(ChangeManager.DOCR_MEMORY_BLOCK_MOVED) ||
|
ev.containsEvent(ChangeManager.DOCR_MEMORY_BLOCK_MOVED) ||
|
||||||
ev.containsEvent(ChangeManager.DOCR_MEMORY_BLOCK_REMOVED)) {
|
ev.containsEvent(ChangeManager.DOCR_MEMORY_BLOCK_REMOVED)) {
|
||||||
|
|
|
@ -106,7 +106,7 @@ public class AboutProgramPlugin extends Plugin implements FrontEndable {
|
||||||
ProgramActionContext pac = (ProgramActionContext) context;
|
ProgramActionContext pac = (ProgramActionContext) context;
|
||||||
Program program = pac.getProgram();
|
Program program = pac.getProgram();
|
||||||
if (program != null) {
|
if (program != null) {
|
||||||
String menuName = "About " + program.getDomainFile().getName() + "...";
|
String menuName = "About " + program.getDomainFile().getName();
|
||||||
getMenuBarData().setMenuItemName(menuName);
|
getMenuBarData().setMenuItemName(menuName);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,6 +134,10 @@ class ReferenceProvider extends ComponentProviderAdapter {
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isBusy() {
|
||||||
|
return referenceKeyModel.isBusy();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void componentHidden() {
|
public void componentHidden() {
|
||||||
referenceKeyModel.setProgram(null);
|
referenceKeyModel.setProgram(null);
|
||||||
|
|
|
@ -151,8 +151,8 @@ class SymbolPanel extends JPanel {
|
||||||
filterDialog.adjustFilter(symProvider, tableModel);
|
filterDialog.adjustFilter(symProvider, tableModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
NewSymbolFilter getFilter() {
|
SymbolFilter getFilter() {
|
||||||
return filterDialog.getFilter();
|
return tableModel.getFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
void readConfigState(SaveState saveState) {
|
void readConfigState(SaveState saveState) {
|
||||||
|
|
|
@ -149,10 +149,14 @@ class SymbolProvider extends ComponentProviderAdapter {
|
||||||
return symbolPanel.getTable();
|
return symbolPanel.getTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
NewSymbolFilter getFilter() {
|
SymbolFilter getFilter() {
|
||||||
return symbolPanel.getFilter();
|
return symbolPanel.getFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isShowingDynamicSymbols() {
|
||||||
|
return getFilter().acceptsDefaultLabelSymbols();
|
||||||
|
}
|
||||||
|
|
||||||
private String generateSubTitle() {
|
private String generateSubTitle() {
|
||||||
SymbolFilter filter = symbolKeyModel.getFilter();
|
SymbolFilter filter = symbolKeyModel.getFilter();
|
||||||
int rowCount = symbolKeyModel.getRowCount();
|
int rowCount = symbolKeyModel.getRowCount();
|
||||||
|
@ -174,11 +178,15 @@ class SymbolProvider extends ComponentProviderAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isBusy() {
|
||||||
|
return symbolKeyModel.isBusy();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void componentHidden() {
|
public void componentHidden() {
|
||||||
symbolKeyModel.reload(null);
|
symbolKeyModel.reload(null);
|
||||||
if (plugin != null) {
|
if (plugin != null) {
|
||||||
plugin.closeReferenceProvider();
|
plugin.symbolProviderClosed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,5 +207,4 @@ class SymbolProvider extends ComponentProviderAdapter {
|
||||||
void writeConfigState(SaveState saveState) {
|
void writeConfigState(SaveState saveState) {
|
||||||
symbolPanel.writeConfigState(saveState);
|
symbolPanel.writeConfigState(saveState);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ public class SymbolReferenceModel extends AddressBasedTableModel<Reference> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TableColumnDescriptor<Reference> createTableColumnDescriptor() {
|
protected TableColumnDescriptor<Reference> createTableColumnDescriptor() {
|
||||||
TableColumnDescriptor<Reference> descriptor = new TableColumnDescriptor<Reference>();
|
TableColumnDescriptor<Reference> descriptor = new TableColumnDescriptor<>();
|
||||||
|
|
||||||
descriptor.addVisibleColumn(
|
descriptor.addVisibleColumn(
|
||||||
DiscoverableTableUtils.adaptColumForModel(this, new ReferenceFromAddressTableColumn()),
|
DiscoverableTableUtils.adaptColumForModel(this, new ReferenceFromAddressTableColumn()),
|
||||||
|
@ -139,7 +139,6 @@ public class SymbolReferenceModel extends AddressBasedTableModel<Reference> {
|
||||||
|
|
||||||
void symbolChanged(Symbol symbol) {
|
void symbolChanged(Symbol symbol) {
|
||||||
if (currentSymbol != null && currentSymbol.equals(symbol)) {
|
if (currentSymbol != null && currentSymbol.equals(symbol)) {
|
||||||
setCurrentSymbol(symbol);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
checkRefs(symbol);
|
checkRefs(symbol);
|
||||||
|
|
|
@ -264,12 +264,13 @@ class SymbolTableModel extends AddressBasedTableModel<Symbol> {
|
||||||
updateObject(Symbol);
|
updateObject(Symbol);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// the symbol may be in the table, as it could have passed the filter before the change
|
||||||
removeObject(Symbol);
|
removeObject(Symbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void delete(List<Symbol> rowObjects) {
|
void delete(List<Symbol> rowObjects) {
|
||||||
if (rowObjects == null || rowObjects.size() == 0) {
|
if (rowObjects == null || rowObjects.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -530,7 +531,7 @@ class SymbolTableModel extends AddressBasedTableModel<Symbol> {
|
||||||
private class SourceTableColumn
|
private class SourceTableColumn
|
||||||
extends AbstractProgramBasedDynamicTableColumn<Symbol, SourceType> {
|
extends AbstractProgramBasedDynamicTableColumn<Symbol, SourceType> {
|
||||||
|
|
||||||
private GColumnRenderer<SourceType> renderer = new AbstractGColumnRenderer<SourceType>() {
|
private GColumnRenderer<SourceType> renderer = new AbstractGColumnRenderer<>() {
|
||||||
@Override
|
@Override
|
||||||
protected String getText(Object value) {
|
protected String getText(Object value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
|
|
|
@ -44,6 +44,9 @@ import ghidra.util.table.GhidraTable;
|
||||||
import ghidra.util.table.SelectionNavigationAction;
|
import ghidra.util.table.SelectionNavigationAction;
|
||||||
import ghidra.util.table.actions.MakeProgramSelectionAction;
|
import ghidra.util.table.actions.MakeProgramSelectionAction;
|
||||||
import ghidra.util.task.SwingUpdateManager;
|
import ghidra.util.task.SwingUpdateManager;
|
||||||
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
import ghidra.util.worker.Job;
|
||||||
|
import ghidra.util.worker.Worker;
|
||||||
import resources.Icons;
|
import resources.Icons;
|
||||||
import resources.ResourceManager;
|
import resources.ResourceManager;
|
||||||
|
|
||||||
|
@ -88,6 +91,13 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||||
private BlockModelService blockModelService;
|
private BlockModelService blockModelService;
|
||||||
private SwingUpdateManager swingMgr;
|
private SwingUpdateManager swingMgr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A worker that will process domain object change event work off of the Swing thread. This
|
||||||
|
* solves the issue of db lock contention that can happen during analysis while this class
|
||||||
|
* attempts to get symbols from the db while processing a flurry of domain events.
|
||||||
|
*/
|
||||||
|
private Worker domainObjectWorker = Worker.createGuiWorker();
|
||||||
|
|
||||||
public SymbolTablePlugin(PluginTool tool) {
|
public SymbolTablePlugin(PluginTool tool) {
|
||||||
super(tool);
|
super(tool);
|
||||||
|
|
||||||
|
@ -124,6 +134,7 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||||
deleteAction.dispose();
|
deleteAction.dispose();
|
||||||
makeSelectionAction.dispose();
|
makeSelectionAction.dispose();
|
||||||
|
|
||||||
|
domainObjectWorker.dispose();
|
||||||
if (symProvider != null) {
|
if (symProvider != null) {
|
||||||
symProvider.dispose();
|
symProvider.dispose();
|
||||||
symProvider = null;
|
symProvider = null;
|
||||||
|
@ -165,17 +176,15 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||||
if (oldProg != null) {
|
if (oldProg != null) {
|
||||||
inspector.setProgram(null);
|
inspector.setProgram(null);
|
||||||
oldProg.removeListener(this);
|
oldProg.removeListener(this);
|
||||||
|
domainObjectWorker.clearAllJobs();
|
||||||
symProvider.setProgram(null, inspector);
|
symProvider.setProgram(null, inspector);
|
||||||
refProvider.setProgram(null, inspector);
|
refProvider.setProgram(null, inspector);
|
||||||
tool.contextChanged(symProvider);
|
tool.contextChanged(symProvider);
|
||||||
}
|
}
|
||||||
currentProgram = newProg;
|
currentProgram = newProg;
|
||||||
if (newProg != null) {
|
if (newProg != null) {
|
||||||
|
|
||||||
currentProgram.addListener(this);
|
currentProgram.addListener(this);
|
||||||
|
|
||||||
inspector.setProgram(currentProgram);
|
inspector.setProgram(currentProgram);
|
||||||
|
|
||||||
symProvider.setProgram(currentProgram, inspector);
|
symProvider.setProgram(currentProgram, inspector);
|
||||||
refProvider.setProgram(currentProgram, inspector);
|
refProvider.setProgram(currentProgram, inspector);
|
||||||
}
|
}
|
||||||
|
@ -184,17 +193,27 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isBusy() {
|
||||||
|
return domainObjectWorker.isBusy() || symProvider.isBusy() || refProvider.isBusy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reload() {
|
||||||
|
domainObjectWorker.clearAllJobs();
|
||||||
|
symProvider.reload();
|
||||||
|
refProvider.reload();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void domainObjectChanged(DomainObjectChangedEvent ev) {
|
public void domainObjectChanged(DomainObjectChangedEvent ev) {
|
||||||
if (!symProvider.isVisible()) {
|
if (!symProvider.isVisible() && !refProvider.isVisible()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ev.containsEvent(DomainObject.DO_OBJECT_RESTORED) ||
|
if (ev.containsEvent(DomainObject.DO_OBJECT_RESTORED) ||
|
||||||
ev.containsEvent(ChangeManager.DOCR_MEMORY_BLOCK_ADDED) ||
|
ev.containsEvent(ChangeManager.DOCR_MEMORY_BLOCK_ADDED) ||
|
||||||
ev.containsEvent(ChangeManager.DOCR_MEMORY_BLOCK_REMOVED)) {
|
ev.containsEvent(ChangeManager.DOCR_MEMORY_BLOCK_REMOVED)) {
|
||||||
|
|
||||||
symProvider.reload();
|
reload();
|
||||||
refProvider.reload();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,103 +227,74 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgramChangeRecord rec = (ProgramChangeRecord) doRecord;
|
ProgramChangeRecord rec = (ProgramChangeRecord) doRecord;
|
||||||
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 = symbolTable.getPrimarySymbol(rec.getStart());
|
domainObjectWorker.schedule(
|
||||||
if (symbol != null && symbol.isDynamic()) {
|
new CodeAddedRemoveJob(currentProgram, rec.getStart()));
|
||||||
symProvider.symbolChanged(symbol);
|
|
||||||
refProvider.symbolChanged(symbol);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ChangeManager.DOCR_SYMBOL_ADDED:
|
case ChangeManager.DOCR_SYMBOL_ADDED:
|
||||||
|
|
||||||
Address addAddr = rec.getStart();
|
Address addAddr = rec.getStart();
|
||||||
Symbol primaryAtAdd = symbolTable.getPrimarySymbol(addAddr);
|
Symbol symbol = (Symbol) rec.getNewValue();
|
||||||
if (primaryAtAdd != null && primaryAtAdd.isDynamic()) {
|
domainObjectWorker.schedule(
|
||||||
symProvider.symbolRemoved(primaryAtAdd);
|
new SymbolAddedJob(currentProgram, symbol, addAddr));
|
||||||
}
|
|
||||||
symbol = (Symbol) rec.getNewValue();
|
|
||||||
symProvider.symbolAdded(symbol);
|
|
||||||
refProvider.symbolAdded(symbol);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
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();
|
||||||
Symbol removedSymbol =
|
domainObjectWorker.schedule(
|
||||||
symbolTable.createSymbolPlaceholder(removeAddr, symbolID);
|
new SymbolRemovedJob(currentProgram, removeAddr, symbolID));
|
||||||
symProvider.symbolRemoved(removedSymbol);
|
|
||||||
refProvider.symbolRemoved(removedSymbol);
|
|
||||||
Symbol primaryAtRemove = symbolTable.getPrimarySymbol(removeAddr);
|
|
||||||
if (primaryAtRemove != null && primaryAtRemove.isDynamic()) {
|
|
||||||
symProvider.symbolAdded(primaryAtRemove);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ChangeManager.DOCR_SYMBOL_RENAMED:
|
case ChangeManager.DOCR_SYMBOL_RENAMED:
|
||||||
case ChangeManager.DOCR_SYMBOL_SCOPE_CHANGED:
|
case ChangeManager.DOCR_SYMBOL_SCOPE_CHANGED:
|
||||||
case ChangeManager.DOCR_SYMBOL_DATA_CHANGED:
|
case ChangeManager.DOCR_SYMBOL_DATA_CHANGED:
|
||||||
|
|
||||||
symbol = (Symbol) rec.getObject();
|
symbol = (Symbol) rec.getObject();
|
||||||
if (!symbol.isDeleted()) { // symbol may have been removed (e.g., parameter)
|
domainObjectWorker.schedule(new SymbolChangedJob(currentProgram, symbol));
|
||||||
symProvider.symbolChanged(symbol);
|
|
||||||
refProvider.symbolChanged(symbol);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ChangeManager.DOCR_SYMBOL_SOURCE_CHANGED:
|
case ChangeManager.DOCR_SYMBOL_SOURCE_CHANGED:
|
||||||
|
|
||||||
symbol = (Symbol) rec.getObject();
|
symbol = (Symbol) rec.getObject();
|
||||||
symProvider.symbolChanged(symbol);
|
domainObjectWorker.schedule(new SymbolSourceChangedJob(currentProgram, symbol));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ChangeManager.DOCR_SYMBOL_SET_AS_PRIMARY:
|
case ChangeManager.DOCR_SYMBOL_SET_AS_PRIMARY:
|
||||||
|
|
||||||
symbol = (Symbol) rec.getNewValue();
|
symbol = (Symbol) rec.getNewValue();
|
||||||
symProvider.symbolChanged(symbol);
|
Symbol oldPrimarySymbol = (Symbol) rec.getOldValue();
|
||||||
Symbol oldSymbol = (Symbol) rec.getOldValue();
|
domainObjectWorker.schedule(
|
||||||
if (oldSymbol != null) {
|
new SymbolSetAsPrimaryJob(currentProgram, symbol, oldPrimarySymbol));
|
||||||
symProvider.symbolChanged(oldSymbol);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ChangeManager.DOCR_SYMBOL_ASSOCIATION_ADDED:
|
case ChangeManager.DOCR_SYMBOL_ASSOCIATION_ADDED:
|
||||||
case ChangeManager.DOCR_SYMBOL_ASSOCIATION_REMOVED:
|
case ChangeManager.DOCR_SYMBOL_ASSOCIATION_REMOVED:
|
||||||
break;
|
break;
|
||||||
case ChangeManager.DOCR_MEM_REFERENCE_ADDED:
|
case ChangeManager.DOCR_MEM_REFERENCE_ADDED:
|
||||||
Reference ref = (Reference) rec.getObject();
|
|
||||||
symbol = symbolTable.getSymbol(ref);
|
|
||||||
if (symbol != null) {
|
|
||||||
symProvider.symbolChanged(symbol);
|
|
||||||
refProvider.symbolChanged(symbol);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ChangeManager.DOCR_MEM_REFERENCE_REMOVED:
|
|
||||||
ref = (Reference) rec.getObject();
|
|
||||||
Address toAddr = ref.getToAddress();
|
|
||||||
if (toAddr.isMemoryAddress()) {
|
|
||||||
symbol = symbolTable.getSymbol(ref);
|
|
||||||
if (symbol == null) {
|
|
||||||
|
|
||||||
long id = symbolTable.getDynamicSymbolID(ref.getToAddress());
|
Reference ref = (Reference) rec.getObject();
|
||||||
removedSymbol = symbolTable.createSymbolPlaceholder(toAddr, id);
|
domainObjectWorker.schedule(new ReferenceAddedJob(currentProgram, ref));
|
||||||
symProvider.symbolRemoved(removedSymbol);
|
break;
|
||||||
}
|
|
||||||
else {
|
case ChangeManager.DOCR_MEM_REFERENCE_REMOVED:
|
||||||
refProvider.symbolChanged(symbol);
|
|
||||||
}
|
ref = (Reference) rec.getObject();
|
||||||
}
|
domainObjectWorker.schedule(new ReferenceRemovedJob(currentProgram, ref));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
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 = symbolTable.getSymbols(rec.getStart());
|
|
||||||
for (Symbol element : symbols) {
|
Address address = rec.getStart();
|
||||||
symProvider.symbolChanged(element);
|
domainObjectWorker.schedule(
|
||||||
refProvider.symbolChanged(element);
|
new ExternalEntryChangedJob(currentProgram, address));
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -336,7 +326,8 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void closeReferenceProvider() {
|
void symbolProviderClosed() {
|
||||||
|
domainObjectWorker.clearAllJobs();
|
||||||
if (refProvider != null) {
|
if (refProvider != null) {
|
||||||
refProvider.closeComponent();
|
refProvider.closeComponent();
|
||||||
}
|
}
|
||||||
|
@ -514,4 +505,268 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||||
action.setSelected(false);
|
action.setSelected(false);
|
||||||
action.setSelected(true);
|
action.setSelected(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Table Update Jobs
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
private abstract class AbstractSymbolUpdateJob extends Job {
|
||||||
|
|
||||||
|
protected Program program;
|
||||||
|
|
||||||
|
AbstractSymbolUpdateJob(Program program) {
|
||||||
|
this.program = program;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void run(TaskMonitor taskMonitor) {
|
||||||
|
if (program != currentProgram) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
doRun();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void doRun();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CodeAddedRemoveJob extends AbstractSymbolUpdateJob {
|
||||||
|
|
||||||
|
private Address start;
|
||||||
|
|
||||||
|
CodeAddedRemoveJob(Program program, Address start) {
|
||||||
|
super(program);
|
||||||
|
this.start = start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRun() {
|
||||||
|
|
||||||
|
if (!symProvider.isShowingDynamicSymbols()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: this code *should* be checking the entire address range to handle the case
|
||||||
|
// where large address range was cleared. This implementation will handle the
|
||||||
|
// case where individual code units are cleared. This feature has been this way
|
||||||
|
// for many years. The assumption is that most users are not showing dynamic
|
||||||
|
// symbols often, especially not when performing analysis or clearing large
|
||||||
|
// address ranges. Checking each address of the changed range is very slow.
|
||||||
|
// This code will need to be updated in the future if we decide updating the
|
||||||
|
// dynamic symbols in the symbol table is worth the cost. For now, if the table
|
||||||
|
// becomes out-of-date, then user can simply close and re-open the table to
|
||||||
|
// trigger an update.
|
||||||
|
SymbolTable symbolTable = currentProgram.getSymbolTable();
|
||||||
|
Symbol symbol = symbolTable.getPrimarySymbol(start);
|
||||||
|
if (symbol != null && symbol.isDynamic()) {
|
||||||
|
symProvider.symbolChanged(symbol);
|
||||||
|
refProvider.symbolChanged(symbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SymbolAddedJob extends AbstractSymbolUpdateJob {
|
||||||
|
|
||||||
|
private Symbol symbol;
|
||||||
|
private Address address;
|
||||||
|
|
||||||
|
SymbolAddedJob(Program program, Symbol symbol, Address address) {
|
||||||
|
super(program);
|
||||||
|
this.symbol = symbol;
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRun() {
|
||||||
|
|
||||||
|
symProvider.symbolAdded(symbol);
|
||||||
|
refProvider.symbolAdded(symbol);
|
||||||
|
|
||||||
|
if (!symProvider.isShowingDynamicSymbols()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SymbolTable symbolTable = program.getSymbolTable();
|
||||||
|
Symbol primaryAtAdd = symbolTable.getPrimarySymbol(address);
|
||||||
|
if (primaryAtAdd != null && primaryAtAdd.isDynamic()) {
|
||||||
|
symProvider.symbolRemoved(primaryAtAdd);
|
||||||
|
refProvider.symbolRemoved(primaryAtAdd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SymbolRemovedJob extends AbstractSymbolUpdateJob {
|
||||||
|
|
||||||
|
private long symbolId;
|
||||||
|
private Address address;
|
||||||
|
|
||||||
|
SymbolRemovedJob(Program program, Address address, long symbolId) {
|
||||||
|
super(program);
|
||||||
|
this.address = address;
|
||||||
|
this.symbolId = symbolId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRun() {
|
||||||
|
|
||||||
|
SymbolTable symbolTable = currentProgram.getSymbolTable();
|
||||||
|
Symbol removedSymbol =
|
||||||
|
symbolTable.createSymbolPlaceholder(address, symbolId);
|
||||||
|
symProvider.symbolRemoved(removedSymbol);
|
||||||
|
refProvider.symbolRemoved(removedSymbol);
|
||||||
|
|
||||||
|
if (!symProvider.isShowingDynamicSymbols()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol primaryAtRemove = symbolTable.getPrimarySymbol(address);
|
||||||
|
if (primaryAtRemove != null && primaryAtRemove.isDynamic()) {
|
||||||
|
symProvider.symbolAdded(primaryAtRemove);
|
||||||
|
refProvider.symbolAdded(primaryAtRemove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SymbolChangedJob extends AbstractSymbolUpdateJob {
|
||||||
|
|
||||||
|
private Symbol symbol;
|
||||||
|
|
||||||
|
SymbolChangedJob(Program program, Symbol symbol) {
|
||||||
|
super(program);
|
||||||
|
this.symbol = symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRun() {
|
||||||
|
|
||||||
|
// Note: should not need this check--the provider should be built to handle this
|
||||||
|
// if (symbol.checkIsValid())
|
||||||
|
symProvider.symbolChanged(symbol);
|
||||||
|
refProvider.symbolChanged(symbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SymbolSourceChangedJob extends AbstractSymbolUpdateJob {
|
||||||
|
|
||||||
|
private Symbol symbol;
|
||||||
|
|
||||||
|
SymbolSourceChangedJob(Program program, Symbol symbol) {
|
||||||
|
super(program);
|
||||||
|
this.symbol = symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRun() {
|
||||||
|
symProvider.symbolChanged(symbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SymbolSetAsPrimaryJob extends AbstractSymbolUpdateJob {
|
||||||
|
|
||||||
|
private Symbol symbol;
|
||||||
|
private Symbol oldPrimarySymbol;
|
||||||
|
|
||||||
|
SymbolSetAsPrimaryJob(Program program, Symbol symbol, Symbol oldPrimarySymbol) {
|
||||||
|
super(program);
|
||||||
|
this.symbol = symbol;
|
||||||
|
this.oldPrimarySymbol = oldPrimarySymbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRun() {
|
||||||
|
|
||||||
|
symProvider.symbolChanged(symbol);
|
||||||
|
if (oldPrimarySymbol != null) {
|
||||||
|
symProvider.symbolChanged(oldPrimarySymbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ReferenceAddedJob extends AbstractSymbolUpdateJob {
|
||||||
|
|
||||||
|
private Reference reference;
|
||||||
|
|
||||||
|
ReferenceAddedJob(Program program, Reference reference) {
|
||||||
|
super(program);
|
||||||
|
this.reference = reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRun() {
|
||||||
|
|
||||||
|
Address toAddr = reference.getToAddress();
|
||||||
|
boolean isValid = toAddr.isMemoryAddress() || toAddr.isExternalAddress();
|
||||||
|
if (!isValid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SymbolTable symbolTable = program.getSymbolTable();
|
||||||
|
Symbol symbol = symbolTable.getSymbol(reference);
|
||||||
|
if (symbol == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!symProvider.isShowingDynamicSymbols() && symbol.isDynamic()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
symProvider.symbolChanged(symbol);
|
||||||
|
refProvider.symbolChanged(symbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ReferenceRemovedJob extends AbstractSymbolUpdateJob {
|
||||||
|
|
||||||
|
private Reference reference;
|
||||||
|
|
||||||
|
ReferenceRemovedJob(Program program, Reference reference) {
|
||||||
|
super(program);
|
||||||
|
this.reference = reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRun() {
|
||||||
|
|
||||||
|
Address toAddr = reference.getToAddress();
|
||||||
|
boolean isValid = toAddr.isMemoryAddress() || toAddr.isExternalAddress();
|
||||||
|
if (!isValid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SymbolTable symbolTable = program.getSymbolTable();
|
||||||
|
Symbol symbol = symbolTable.getSymbol(reference);
|
||||||
|
if (symbol != null) {
|
||||||
|
symProvider.symbolChanged(symbol);
|
||||||
|
refProvider.symbolChanged(symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symProvider.isShowingDynamicSymbols()) {
|
||||||
|
long id = symbolTable.getDynamicSymbolID(reference.getToAddress());
|
||||||
|
Symbol removedSymbol = symbolTable.createSymbolPlaceholder(toAddr, id);
|
||||||
|
symProvider.symbolRemoved(removedSymbol);
|
||||||
|
refProvider.symbolRemoved(removedSymbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ExternalEntryChangedJob extends AbstractSymbolUpdateJob {
|
||||||
|
|
||||||
|
private Address address;
|
||||||
|
|
||||||
|
ExternalEntryChangedJob(Program program, Address address) {
|
||||||
|
super(program);
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRun() {
|
||||||
|
|
||||||
|
SymbolTable symbolTable = program.getSymbolTable();
|
||||||
|
Symbol[] symbols = symbolTable.getSymbols(address);
|
||||||
|
for (Symbol element : symbols) {
|
||||||
|
symProvider.symbolChanged(element);
|
||||||
|
refProvider.symbolChanged(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,6 @@ import docking.action.DockingActionIf;
|
||||||
import docking.action.ToggleDockingAction;
|
import docking.action.ToggleDockingAction;
|
||||||
import docking.widgets.filter.*;
|
import docking.widgets.filter.*;
|
||||||
import docking.widgets.table.*;
|
import docking.widgets.table.*;
|
||||||
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.cmd.refs.RemoveReferenceCmd;
|
||||||
|
@ -273,7 +272,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
pressButtonByText(filterDialog1, "OK");
|
pressButtonByText(filterDialog1, "OK");
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Functions: 'ghidra', 'func_with_parms'
|
// Functions: 'ghidra', 'func_with_parms'
|
||||||
|
@ -294,7 +293,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
pressButtonByText(filterDialog2, "OK");
|
pressButtonByText(filterDialog2, "OK");
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Entry Points: 'entry'
|
// Entry Points: 'entry'
|
||||||
|
@ -314,7 +313,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
});
|
});
|
||||||
pressButtonByText(filterDialog3, "OK");
|
pressButtonByText(filterDialog3, "OK");
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Locals: 'AnotherLocal', 'MyLocal'
|
// Locals: 'AnotherLocal', 'MyLocal'
|
||||||
|
@ -348,7 +347,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
public void testEditing() throws Exception {
|
public void testEditing() throws Exception {
|
||||||
openProgram("sample");
|
openProgram("sample");
|
||||||
|
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
|
|
||||||
String symbolName = "ghidra";
|
String symbolName = "ghidra";
|
||||||
int row = findRow(symbolName);
|
int row = findRow(symbolName);
|
||||||
|
@ -367,7 +366,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
myTypeText(editor, ".Is.Cool");
|
myTypeText(editor, ".Is.Cool");
|
||||||
runSwing(() -> symbolTable.editingStopped(new ChangeEvent(symbolTable)));
|
runSwing(() -> symbolTable.editingStopped(new ChangeEvent(symbolTable)));
|
||||||
|
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
|
|
||||||
assertTrue(!symbolTable.isEditing());
|
assertTrue(!symbolTable.isEditing());
|
||||||
|
|
||||||
|
@ -391,7 +390,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
st.createLabel(sample.getNewAddress(0x01008500), "abc123", SourceType.USER_DEFINED);
|
st.createLabel(sample.getNewAddress(0x01008500), "abc123", SourceType.USER_DEFINED);
|
||||||
});
|
});
|
||||||
|
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
int testTimeoutMs = 100;
|
int testTimeoutMs = 100;
|
||||||
symbolTable.setAutoLookupTimeout(testTimeoutMs);
|
symbolTable.setAutoLookupTimeout(testTimeoutMs);
|
||||||
|
|
||||||
|
@ -432,7 +431,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
assertTrue(deleteAction.isEnabled());
|
assertTrue(deleteAction.isEnabled());
|
||||||
performAction(deleteAction, true);
|
performAction(deleteAction, true);
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
|
|
||||||
assertNull(getUniqueSymbol(program, "ghidra"));
|
assertNull(getUniqueSymbol(program, "ghidra"));
|
||||||
Symbol myLocalSymbol = getUniqueSymbol(program, "MyLocal");
|
Symbol myLocalSymbol = getUniqueSymbol(program, "MyLocal");
|
||||||
|
@ -462,7 +461,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
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.
|
||||||
|
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
|
|
||||||
// 1 Data label removed
|
// 1 Data label removed
|
||||||
int expected = rowCount - 1;
|
int expected = rowCount - 1;
|
||||||
|
@ -566,7 +565,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
assertFalse(clearPinnedAction.isEnabledForContext(actionContext));
|
assertFalse(clearPinnedAction.isEnabledForContext(actionContext));
|
||||||
|
|
||||||
performAction(setPinnedAction, actionContext, true);
|
performAction(setPinnedAction, actionContext, true);
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
for (int selectedRow : selectedRows) {
|
for (int selectedRow : selectedRows) {
|
||||||
Symbol symbol = getSymbol(selectedRow);
|
Symbol symbol = getSymbol(selectedRow);
|
||||||
assertTrue(symbol.isPinned());
|
assertTrue(symbol.isPinned());
|
||||||
|
@ -611,7 +610,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
return st.createLabel(sample.getNewAddress(0x01007000), "Zeus",
|
return st.createLabel(sample.getNewAddress(0x01007000), "Zeus",
|
||||||
SourceType.USER_DEFINED);
|
SourceType.USER_DEFINED);
|
||||||
});
|
});
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
assertEquals(rowCount + 1, symbolTable.getRowCount());
|
assertEquals(rowCount + 1, symbolTable.getRowCount());
|
||||||
assertTrue(symbolModel.getRowIndex(sym) >= 0);
|
assertTrue(symbolModel.getRowIndex(sym) >= 0);
|
||||||
|
|
||||||
|
@ -619,7 +618,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
return st.createLabel(sample.getNewAddress(0x01007100), "Athena",
|
return st.createLabel(sample.getNewAddress(0x01007100), "Athena",
|
||||||
SourceType.USER_DEFINED);
|
SourceType.USER_DEFINED);
|
||||||
});
|
});
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
assertEquals(rowCount + 2, symbolTable.getRowCount());
|
assertEquals(rowCount + 2, symbolTable.getRowCount());
|
||||||
assertTrue(symbolModel.getRowIndex(sym) >= 0);
|
assertTrue(symbolModel.getRowIndex(sym) >= 0);
|
||||||
}
|
}
|
||||||
|
@ -648,7 +647,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
return st.createLabel(sample.getNewAddress(0x01007000), "saaaa",
|
return st.createLabel(sample.getNewAddress(0x01007000), "saaaa",
|
||||||
SourceType.USER_DEFINED);
|
SourceType.USER_DEFINED);
|
||||||
});
|
});
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
assertTrue(symbolModel.getRowIndex(sym) >= 0);
|
assertTrue(symbolModel.getRowIndex(sym) >= 0);
|
||||||
|
|
||||||
// make sure we added one while the filter is on
|
// make sure we added one while the filter is on
|
||||||
|
@ -672,7 +671,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
pressButtonByText(filterDialog1, "OK");
|
pressButtonByText(filterDialog1, "OK");
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Functions: 'ghidra', 'func_with_parms'
|
// Functions: 'ghidra', 'func_with_parms'
|
||||||
|
@ -696,7 +695,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
assertNull(getUniqueSymbol(program, "EXT_00000051"));
|
assertNull(getUniqueSymbol(program, "EXT_00000051"));
|
||||||
|
|
||||||
tx(program, () -> st.removeSymbolSpecial(sym));
|
tx(program, () -> st.removeSymbolSpecial(sym));
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
|
|
||||||
// entry symbol replaced by dynamic External Entry symbol
|
// entry symbol replaced by dynamic External Entry symbol
|
||||||
assertNull(getUniqueSymbol(program, "entry"));
|
assertNull(getUniqueSymbol(program, "entry"));
|
||||||
|
@ -723,7 +722,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
rm.setPrimary(ref, true);
|
rm.setPrimary(ref, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
|
|
||||||
row = symbolModel.getRowIndex(s);
|
row = symbolModel.getRowIndex(s);
|
||||||
|
|
||||||
|
@ -752,7 +751,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
manager.delete(ref);
|
manager.delete(ref);
|
||||||
});
|
});
|
||||||
|
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
|
|
||||||
refCount = getRefCount(row);
|
refCount = getRefCount(row);
|
||||||
assertNotNull(refCount);
|
assertNotNull(refCount);
|
||||||
|
@ -782,19 +781,19 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
ClearCmd cmd = new ClearCmd(program.getMemory(), new ClearOptions());
|
ClearCmd cmd = new ClearCmd(program.getMemory(), new ClearOptions());
|
||||||
applyCmd(program, cmd);
|
applyCmd(program, cmd);
|
||||||
waitForBusyTool(tool);
|
waitForBusyTool(tool);
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
|
|
||||||
// Externals are not cleared
|
// Externals are not cleared
|
||||||
int clearedRowCount = 3;
|
int clearedRowCount = 3;
|
||||||
assertEquals(clearedRowCount, symbolTable.getRowCount());
|
assertEquals(clearedRowCount, symbolTable.getRowCount());
|
||||||
|
|
||||||
undo(program);
|
undo(program);
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
|
|
||||||
assertEquals(startRowCount, symbolTable.getRowCount());
|
assertEquals(startRowCount, symbolTable.getRowCount());
|
||||||
|
|
||||||
redo(program);
|
redo(program);
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
|
|
||||||
assertEquals(clearedRowCount, symbolTable.getRowCount());
|
assertEquals(clearedRowCount, symbolTable.getRowCount());
|
||||||
}
|
}
|
||||||
|
@ -815,7 +814,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
pressButtonByText(filterDialog, "OK");
|
pressButtonByText(filterDialog, "OK");
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -880,8 +879,8 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
performAction(refsToAction, true);
|
performAction(refsToAction, true);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
waitForNotBusy(referenceTable);
|
waitForNotBusy();
|
||||||
assertEquals(4, referenceTable.getRowCount());
|
assertEquals(4, referenceTable.getRowCount());
|
||||||
|
|
||||||
assertReferencesAddressColumnValue(0, 0x54);
|
assertReferencesAddressColumnValue(0, 0x54);
|
||||||
|
@ -899,8 +898,8 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
waitForNotBusy(referenceTable);
|
waitForNotBusy();
|
||||||
assertEquals(3, referenceTable.getRowCount());
|
assertEquals(3, referenceTable.getRowCount());
|
||||||
|
|
||||||
assertReferencesAddressColumnValue(0, 0x53);
|
assertReferencesAddressColumnValue(0, 0x53);
|
||||||
|
@ -917,8 +916,8 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
waitForNotBusy(referenceTable);
|
waitForNotBusy();
|
||||||
assertEquals(2, referenceTable.getRowCount());
|
assertEquals(2, referenceTable.getRowCount());
|
||||||
|
|
||||||
// data
|
// data
|
||||||
|
@ -1085,33 +1084,33 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
addLabel("bob", null, addr("010058f6"));
|
addLabel("bob", null, addr("010058f6"));
|
||||||
|
|
||||||
addLabel("bob", "billy", addr("01005917"));
|
addLabel("bob", "billy", addr("01005917"));
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
|
|
||||||
int updatedRowCount = symbolTable.getRowCount();
|
int updatedRowCount = symbolTable.getRowCount();
|
||||||
assertEquals(rowCount + 2, updatedRowCount);
|
assertEquals(rowCount + 2, updatedRowCount);
|
||||||
|
|
||||||
// test ascending
|
// test ascending
|
||||||
runSwing(() -> TableUtils.columnSelected(symbolTable, 0));
|
runSwing(() -> TableUtils.columnSelected(symbolTable, 0));
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
|
|
||||||
setFilterOptions(TextFilterStrategy.STARTS_WITH, false);
|
setFilterOptions(TextFilterStrategy.STARTS_WITH, false);
|
||||||
|
|
||||||
myTypeText(textField, "bo");
|
myTypeText(textField, "bo");
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
|
|
||||||
// make sure both 'bob's are in the table
|
// make sure both 'bob's are in the table
|
||||||
assertEquals("Did not find two bobs.", 2, symbolTable.getRowCount());
|
assertEquals("Did not find two bobs.", 2, symbolTable.getRowCount());
|
||||||
modelMatchesIgnoringCase("bob");
|
modelMatchesIgnoringCase("bob");
|
||||||
|
|
||||||
myTypeText(textField, "b");
|
myTypeText(textField, "b");
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
|
|
||||||
assertEquals("Did not find two bobs.", 2, symbolTable.getRowCount());
|
assertEquals("Did not find two bobs.", 2, symbolTable.getRowCount());
|
||||||
modelMatchesIgnoringCase("bob");
|
modelMatchesIgnoringCase("bob");
|
||||||
|
|
||||||
// test descending
|
// test descending
|
||||||
runSwing(() -> TableUtils.columnSelected(symbolTable, 0));
|
runSwing(() -> TableUtils.columnSelected(symbolTable, 0));
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
|
|
||||||
assertEquals("Did not find two bobs in descending order.", 2, symbolTable.getRowCount());
|
assertEquals("Did not find two bobs in descending order.", 2, symbolTable.getRowCount());
|
||||||
modelMatchesIgnoringCase("bob");
|
modelMatchesIgnoringCase("bob");
|
||||||
|
@ -1250,12 +1249,12 @@ 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);
|
waitForNotBusy();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setName(Symbol symbol, String name, SourceType type) throws Exception {
|
private void setName(Symbol symbol, String name, SourceType type) throws Exception {
|
||||||
tx(program, () -> symbol.setName(name, SourceType.DEFAULT));
|
tx(program, () -> symbol.setName(name, SourceType.DEFAULT));
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Symbol getSymbol(int row) {
|
private Symbol getSymbol(int row) {
|
||||||
|
@ -1315,7 +1314,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
private void setFilterOptions(TextFilterStrategy filterStrategy, boolean caseSensitive)
|
private void setFilterOptions(TextFilterStrategy filterStrategy, boolean caseSensitive)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
filterPanel.setFilterOptions(new FilterOptions(filterStrategy, true, caseSensitive, false));
|
filterPanel.setFilterOptions(new FilterOptions(filterStrategy, true, caseSensitive, false));
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
}
|
}
|
||||||
|
|
||||||
private JTextField getFilterTextField() {
|
private JTextField getFilterTextField() {
|
||||||
|
@ -1351,7 +1350,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
pressButtonByText(filterDialog, "OK", true);
|
pressButtonByText(filterDialog, "OK", true);
|
||||||
|
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getRowForSymbol(Symbol symbol) {
|
private int getRowForSymbol(Symbol symbol) {
|
||||||
|
@ -1390,7 +1389,7 @@ 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, program);
|
tool.execute(command, program);
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Address addr(String address) {
|
private Address addr(String address) {
|
||||||
|
@ -1399,7 +1398,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
private void myTypeText(Component c, String text) throws Exception {
|
private void myTypeText(Component c, String text) throws Exception {
|
||||||
triggerText(c, text);
|
triggerText(c, text);
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteTextFieldText(JTextField textField) {
|
private void deleteTextFieldText(JTextField textField) {
|
||||||
|
@ -1410,7 +1409,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
try {
|
try {
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
}
|
}
|
||||||
catch (Exception exc) {
|
catch (Exception exc) {
|
||||||
// we don't care
|
// we don't care
|
||||||
|
@ -1419,7 +1418,7 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
private void typeBackspaceOnComponent(Component component) throws Exception {
|
private void typeBackspaceOnComponent(Component component) throws Exception {
|
||||||
triggerActionKey(component, 0, KeyEvent.VK_BACK_SPACE);
|
triggerActionKey(component, 0, KeyEvent.VK_BACK_SPACE);
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
}
|
}
|
||||||
|
|
||||||
// makes sure that all of the symbols in the model start with the given string
|
// makes sure that all of the symbols in the model start with the given string
|
||||||
|
@ -1459,10 +1458,9 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void waitForNotBusy(GTable table) throws Exception {
|
private void waitForNotBusy() throws Exception {
|
||||||
waitForProgram(program);
|
waitForProgram(program);
|
||||||
ThreadedTableModel<?, ?> model = (ThreadedTableModel<?, ?>) table.getModel();
|
waitForCondition(() -> !plugin.isBusy());
|
||||||
waitForTableModel(model);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openProgram(String name) throws Exception {
|
private void openProgram(String name) throws Exception {
|
||||||
|
@ -1583,9 +1581,9 @@ public class SymbolTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
filter.setFilter("Function Labels", true);
|
filter.setFilter("Function Labels", true);
|
||||||
filter.setFilter("Default (Functions)", true);
|
filter.setFilter("Default (Functions)", true);
|
||||||
filter.setFilter("Default (Labels)", true);
|
filter.setFilter("Default (Labels)", true);
|
||||||
symbolModel.setFilter(filter);
|
runSwing(() -> symbolModel.setFilter(filter));
|
||||||
|
|
||||||
waitForNotBusy(symbolTable);
|
waitForNotBusy();
|
||||||
|
|
||||||
sortAscending(SymbolTableModel.LABEL_COL);
|
sortAscending(SymbolTableModel.LABEL_COL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,12 +153,32 @@ public class TableData<ROW_OBJECT> implements Iterable<ROW_OBJECT> {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean remove(ROW_OBJECT o) {
|
boolean remove(ROW_OBJECT t) {
|
||||||
if (source != null) {
|
if (source != null) {
|
||||||
source.remove(o);
|
source.remove(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
return data.remove(o);
|
if (sortContext.isUnsorted()) {
|
||||||
|
return data.remove(t); // no sort; cannot binary search
|
||||||
|
}
|
||||||
|
|
||||||
|
Comparator<ROW_OBJECT> comparator = sortContext.getComparator();
|
||||||
|
int index = Collections.binarySearch(data, t, comparator);
|
||||||
|
if (index > 0) {
|
||||||
|
data.remove(index);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// At this point we have one of 2 conditions: the object is not in the list, or the object
|
||||||
|
// does not work with the current sort comparator.
|
||||||
|
//
|
||||||
|
// There are cases where the comparator will not work for the object handed to this method,
|
||||||
|
// such as when some db objects get deleted and the client uses a proxy object to perform
|
||||||
|
// the delete. To handle these odd cases, we still have to brute-force search. If this
|
||||||
|
// proves to be a bottleneck, then we can update how we handle item removal.
|
||||||
|
//
|
||||||
|
return data.remove(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue