diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchmem/MemSearchPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchmem/MemSearchPlugin.java index 57dacdb0e5..5dcfe23bee 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchmem/MemSearchPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchmem/MemSearchPlugin.java @@ -17,8 +17,7 @@ package ghidra.app.plugin.core.searchmem; import java.awt.Color; import java.awt.event.KeyEvent; -import java.util.Collections; -import java.util.List; +import java.util.*; import javax.swing.ImageIcon; import javax.swing.JComponent; @@ -635,6 +634,8 @@ public class MemSearchPlugin extends Plugin implements OptionsChangeListener, abstract List getMatches(); + abstract void cleanup(); + private List getAddressesFoundInRange(Address start, Address end) { List data = getMatches(); int startIndex = findFirstIndex(data, start, end); @@ -766,12 +767,14 @@ public class MemSearchPlugin extends Plugin implements OptionsChangeListener, if (provider != null) { // search all - remove highlights when if (!tool.isVisible(provider)) { // results are no longer showing highlightNavigatable.removeHighlightProvider(this, highlightProgram); + cleanup(); return true; } } else if (!searchDialog.isVisible()) { // single search - remove highlights when search dialog no longer showing highlightNavigatable.removeHighlightProvider(this, highlightProgram); + cleanup(); return true; } return false; @@ -791,16 +794,64 @@ public class MemSearchPlugin extends Plugin implements OptionsChangeListener, private class SearchTableHighlightHandler extends SearchResultsHighlighter { private final MemSearchTableModel model; + private List sortedResults; SearchTableHighlightHandler(Navigatable navigatable, MemSearchTableModel model, TableComponentProvider provider, Program program) { super(navigatable, provider, program); this.model = model; + + model.addThreadedTableModelListener(new ThreadedTableModelListener() { + + @Override + public void loadingStarted() { + clearCache(); + } + + @Override + public void loadingFinished(boolean wasCancelled) { + // stub + } + + @Override + public void loadPending() { + clearCache(); + } + }); } @Override List getMatches() { - return model.getModelData(); + + if (sortedResults != null) { + return sortedResults; + } + + if (model.isBusy()) { + return Collections.emptyList(); + } + + List modelData = model.getModelData(); + if (model.isSortedOnAddress()) { + return modelData; + } + + sortedResults = new ArrayList<>(modelData); + Collections.sort(sortedResults); + + return sortedResults; + } + + @Override + void cleanup() { + clearCache(); + } + + private void clearCache() { + if (sortedResults != null) { + sortedResults.clear(); + sortedResults = null; + } } } @@ -817,6 +868,11 @@ public class MemSearchPlugin extends Plugin implements OptionsChangeListener, List getMatches() { return searchTask.getMatchingAddresses(); } + + @Override + void cleanup() { + // nothing to do + } } private class SearchOnceTaskListener implements TaskListener { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchmem/MemSearchTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchmem/MemSearchTableModel.java index 683e298702..a941131230 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchmem/MemSearchTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchmem/MemSearchTableModel.java @@ -15,6 +15,7 @@ */ package ghidra.app.plugin.core.searchmem; +import docking.widgets.table.*; import ghidra.framework.plugintool.ServiceProvider; import ghidra.program.model.address.*; import ghidra.program.model.listing.Program; @@ -23,6 +24,7 @@ import ghidra.util.datastruct.Accumulator; import ghidra.util.exception.CancelledException; import ghidra.util.search.memory.*; import ghidra.util.table.AddressBasedTableModel; +import ghidra.util.table.field.AddressTableColumn; import ghidra.util.task.TaskMonitor; public class MemSearchTableModel extends AddressBasedTableModel { @@ -44,6 +46,22 @@ public class MemSearchTableModel extends AddressBasedTableModel this.selectionSize = selectionSize; } + public boolean isSortedOnAddress() { + TableSortState sortState = getTableSortState(); + if (sortState.isUnsorted()) { + return false; + } + + ColumnSortState primaryState = sortState.getAllSortStates().get(0); + DynamicTableColumn column = + getColumn(primaryState.getColumnModelIndex()); + String name = column.getColumnName(); + if (AddressTableColumn.NAME.equals(name)) { + return true; + } + return false; + } + @Override protected void doLoad(Accumulator accumulator, TaskMonitor monitor) throws CancelledException { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/AddressTableColumn.java b/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/AddressTableColumn.java index 312172801c..cbf49b6b18 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/AddressTableColumn.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/util/table/field/AddressTableColumn.java @@ -28,6 +28,8 @@ import ghidra.program.util.ProgramLocation; public class AddressTableColumn extends ProgramLocationTableColumnExtensionPoint { + public static final String NAME = "Location"; + @Override public String getColumnDisplayName(Settings settings) { return getColumnName(); @@ -35,7 +37,7 @@ public class AddressTableColumn @Override public String getColumnName() { - return "Location"; + return NAME; } @Override