diff --git a/Ghidra/Features/Base/src/main/java/ghidra/GhidraOptions.java b/Ghidra/Features/Base/src/main/java/ghidra/GhidraOptions.java index f55db72821..2bd80aaffb 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/GhidraOptions.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/GhidraOptions.java @@ -4,9 +4,9 @@ * 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. @@ -18,6 +18,7 @@ package ghidra; import java.awt.event.MouseEvent; import generic.theme.GColor; +import ghidra.app.util.SearchConstants; import ghidra.framework.options.Options; /** @@ -82,13 +83,17 @@ public interface GhidraOptions { /** * Option for the max number of hits found in a search; the search * stops when it reaches this limit. + * @deprecated use {@link SearchConstants#SEARCH_LIMIT_NAME} */ - final String OPTION_SEARCH_LIMIT = "Search Limit"; + @Deprecated + final String OPTION_SEARCH_LIMIT = SearchConstants.SEARCH_LIMIT_NAME; /** * Options title the search category + * @deprecated use {@link SearchConstants#SEARCH_OPTION_NAME} */ - final String OPTION_SEARCH_TITLE = "Search"; + @Deprecated(since = "11.3", forRemoval = true) + final String OPTION_SEARCH_TITLE = SearchConstants.SEARCH_OPTION_NAME; /** * Category name for the "Auto Analysis" options. diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/AddressRangeTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/AddressRangeTableModel.java index 2f6436fcd1..70b892d306 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/AddressRangeTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/AddressRangeTableModel.java @@ -4,9 +4,9 @@ * 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. @@ -39,8 +39,10 @@ import ghidra.util.task.TaskMonitor; */ public class AddressRangeTableModel extends GhidraProgramTableModel { - private ProgramSelection selection; + private static final int MIN_ADDRESS_COLUMN_INDEX = 0; private static final int MAX_ADDRESS_COLUMN_INDEX = 1; + + private ProgramSelection selection; private int resultsLimit; private long minLength; @@ -52,24 +54,6 @@ public class AddressRangeTableModel extends GhidraProgramTableModel accumulator, TaskMonitor monitor) throws CancelledException { @@ -140,6 +124,42 @@ public class AddressRangeTableModel extends GhidraProgramTableModel { @@ -235,20 +255,19 @@ public class AddressRangeTableModel extends GhidraProgramTableModel { + private class NumRefsFromTableColumn + extends AbstractDynamicTableColumn { - @Override - public String getColumnName() { - return "From References"; - } - - @Override - public Integer getValue(AddressRangeInfo rangeInfo, Settings settings, Object data, - ServiceProvider services) throws IllegalArgumentException { - return rangeInfo.numRefsFrom(); - } + @Override + public String getColumnName() { + return "From References"; } + @Override + public Integer getValue(AddressRangeInfo rangeInfo, Settings settings, Object data, + ServiceProvider services) throws IllegalArgumentException { + return rangeInfo.numRefsFrom(); + } + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/gotoquery/GoToServicePlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/gotoquery/GoToServicePlugin.java index 67c452d910..0e4cb2ddf9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/gotoquery/GoToServicePlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/gotoquery/GoToServicePlugin.java @@ -4,9 +4,9 @@ * 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. @@ -17,7 +17,6 @@ package ghidra.app.plugin.core.gotoquery; import javax.swing.Icon; -import ghidra.GhidraOptions; import ghidra.app.CorePluginPackage; import ghidra.app.events.*; import ghidra.app.nav.*; @@ -67,7 +66,7 @@ public final class GoToServicePlugin extends ProgramPlugin { Options opt = tool.getOptions(SearchConstants.SEARCH_OPTION_NAME); // we register this option here, since the other search plugins all depend on this service - opt.registerOption(GhidraOptions.OPTION_SEARCH_LIMIT, + opt.registerOption(SearchConstants.SEARCH_LIMIT_NAME, SearchConstants.DEFAULT_SEARCH_LIMIT, null, "The maximum number of search results."); @@ -90,7 +89,7 @@ public final class GoToServicePlugin extends ProgramPlugin { int getMaxHits() { Options opt = tool.getOptions(SearchConstants.SEARCH_OPTION_NAME); int maxSearchHits = - opt.getInt(GhidraOptions.OPTION_SEARCH_LIMIT, SearchConstants.DEFAULT_SEARCH_LIMIT); + opt.getInt(SearchConstants.SEARCH_LIMIT_NAME, SearchConstants.DEFAULT_SEARCH_LIMIT); return maxSearchHits; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesHighlighter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesHighlighter.java index 3bc0899214..bb906ce98f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesHighlighter.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesHighlighter.java @@ -4,9 +4,9 @@ * 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. @@ -23,6 +23,7 @@ import ghidra.GhidraOptions; import ghidra.app.nav.Navigatable; import ghidra.app.services.*; import ghidra.app.util.ListingHighlightProvider; +import ghidra.app.util.SearchConstants; import ghidra.app.util.viewer.field.ListingField; import ghidra.app.util.viewer.proxy.ProxyObj; import ghidra.framework.options.OptionsChangeListener; @@ -39,7 +40,7 @@ class LocationReferencesHighlighter { private static final String MARKER_SET_DESCRIPTION = "Shows the location of references " + "currently displayed in the Location References window."; - private static final String OPTIONS_TITLE = GhidraOptions.OPTION_SEARCH_TITLE; + private static final String OPTIONS_TITLE = SearchConstants.SEARCH_OPTION_NAME; private static final String HIGHLIGHT_COLOR_KEY = "Reference Search" + GhidraOptions.DELIMITER + "Highlight Match Color"; private static final String HIGHLIGHT_COLOR_DESCRIPTION = diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reachability/FunctionReachabilityTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reachability/FunctionReachabilityTableModel.java index 2722bddd9a..b50b0fc62f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reachability/FunctionReachabilityTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reachability/FunctionReachabilityTableModel.java @@ -4,9 +4,9 @@ * 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. @@ -200,14 +200,28 @@ public class FunctionReachabilityTableModel } @Override - public ProgramLocation getProgramLocation(int row, int column) { - FunctionReachabilityResult result = getRowObject(row); - if (column == FROM_FUNCTION_COLUMN) { + public Address getAddress(int modelRow, int modelColumn) { + FunctionReachabilityResult result = getRowObject(modelColumn); + if (modelColumn == FROM_FUNCTION_COLUMN) { + Function function = result.getFromFunction(); + return function.getEntryPoint(); + } + else if (modelColumn == TO_FUNCTION_COLUMN) { + Function function = result.getToFunction(); + return function.getEntryPoint(); + } + return null; + } + + @Override + public ProgramLocation getProgramLocation(int modelRow, int modelColumn) { + FunctionReachabilityResult result = getRowObject(modelRow); + if (modelColumn == FROM_FUNCTION_COLUMN) { Function function = result.getFromFunction(); Address address = function.getEntryPoint(); return new ProgramLocation(getProgram(), address); } - else if (column == TO_FUNCTION_COLUMN) { + else if (modelColumn == TO_FUNCTION_COLUMN) { Function function = result.getToFunction(); Address address = function.getEntryPoint(); return new ProgramLocation(getProgram(), address); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/AbstractSearchTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/AbstractSearchTableModel.java index 652295a048..d8af0b33f5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/AbstractSearchTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/AbstractSearchTableModel.java @@ -4,9 +4,9 @@ * 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. @@ -15,7 +15,6 @@ */ package ghidra.app.plugin.core.searchtext; -import ghidra.GhidraOptions; import ghidra.app.plugin.core.searchtext.Searcher.TextSearchResult; import ghidra.app.util.SearchConstants; import ghidra.app.util.query.ProgramLocationPreviewTableModel; @@ -51,7 +50,7 @@ public abstract class AbstractSearchTableModel extends ProgramLocationPreviewTab this.options = options; Options opt = tool.getOptions(SearchConstants.SEARCH_OPTION_NAME); searchLimit = - opt.getInt(GhidraOptions.OPTION_SEARCH_LIMIT, SearchConstants.DEFAULT_SEARCH_LIMIT); + opt.getInt(SearchConstants.SEARCH_LIMIT_NAME, SearchConstants.DEFAULT_SEARCH_LIMIT); } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin.java index 8f25e2ee8b..eacc2d6ba6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin.java @@ -4,9 +4,9 @@ * 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. @@ -31,7 +31,6 @@ import docking.tool.ToolConstants; import docking.widgets.fieldpanel.support.Highlight; import docking.widgets.table.threaded.*; import generic.theme.GIcon; -import ghidra.GhidraOptions; import ghidra.app.CorePluginPackage; import ghidra.app.context.*; import ghidra.app.nav.Navigatable; @@ -423,7 +422,7 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList @Override public void optionsChanged(ToolOptions options, String optionName, Object oldValue, Object newValue) { - if (optionName.equals(GhidraOptions.OPTION_SEARCH_LIMIT)) { + if (optionName.equals(SearchConstants.SEARCH_LIMIT_NAME)) { int newSearchLimit = ((Integer) newValue).intValue(); if (newSearchLimit <= 0) { throw new OptionsVetoException("Search limit must be greater than 0"); @@ -450,7 +449,7 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList "The search result highlight color for the currently selected match"); searchLimit = - opt.getInt(GhidraOptions.OPTION_SEARCH_LIMIT, SearchConstants.DEFAULT_SEARCH_LIMIT); + opt.getInt(SearchConstants.SEARCH_LIMIT_NAME, SearchConstants.DEFAULT_SEARCH_LIMIT); doHighlight = opt.getBoolean(SearchConstants.SEARCH_HIGHLIGHT_NAME, true); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/SearchConstants.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/SearchConstants.java index f497626685..51be294acc 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/SearchConstants.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/SearchConstants.java @@ -4,9 +4,9 @@ * 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. @@ -32,6 +32,12 @@ public interface SearchConstants { */ public static final String SEARCH_OPTION_NAME = "Search"; + /** + * Option for the max number of hits found in a search; the search + * stops when it reaches this limit. + */ + public static final String SEARCH_LIMIT_NAME = "Search Limit"; + /** * Option name for whether to highlight search results. */ diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/navigation/GoToQuery.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/navigation/GoToQuery.java index dbbd62894f..8633016b35 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/navigation/GoToQuery.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/navigation/GoToQuery.java @@ -19,7 +19,6 @@ import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; -import ghidra.GhidraOptions; import ghidra.app.nav.Navigatable; import ghidra.app.plugin.core.gotoquery.GoToQueryResultsTableModel; import ghidra.app.plugin.core.navigation.NavigationOptions; @@ -75,7 +74,7 @@ public class GoToQuery { Options options = plugin.getTool().getOptions(SearchConstants.SEARCH_OPTION_NAME); this.maxHits = - options.getInt(GhidraOptions.OPTION_SEARCH_LIMIT, SearchConstants.DEFAULT_SEARCH_LIMIT); + options.getInt(SearchConstants.SEARCH_LIMIT_NAME, SearchConstants.DEFAULT_SEARCH_LIMIT); this.fromAddress = fromAddr; this.monitor = monitor; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemorySearchOptions.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemorySearchOptions.java index 1f8f61194d..c4698eb79b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemorySearchOptions.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemorySearchOptions.java @@ -15,7 +15,6 @@ */ package ghidra.features.base.memsearch.gui; -import static ghidra.GhidraOptions.*; import static ghidra.app.util.SearchConstants.*; import ghidra.GhidraOptions; @@ -113,7 +112,7 @@ public class MemorySearchOptions { private void searchOptionsChanged(ToolOptions options, String optionName, Object oldValue, Object newValue) { - if (optionName.equals(OPTION_SEARCH_LIMIT)) { + if (optionName.equals(SEARCH_LIMIT_NAME)) { int limit = (int) newValue; if (limit <= 0) { throw new OptionsVetoException("Search limit must be greater than 0"); @@ -125,7 +124,7 @@ public class MemorySearchOptions { } private void loadSearchOptions(ToolOptions options) { - searchLimit = options.getInt(OPTION_SEARCH_LIMIT, DEFAULT_SEARCH_LIMIT); + searchLimit = options.getInt(SEARCH_LIMIT_NAME, DEFAULT_SEARCH_LIMIT); highlightMatches = options.getBoolean(SEARCH_HIGHLIGHT_NAME, true); autoRestrictSelection = options.getBoolean(AUTO_RESTRICT_SELECTION, true); prepopulateSearch = options.getBoolean(PRE_POPULATE_MEM_SEARCH, true); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/table/AddressBasedTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/util/table/AddressBasedTableModel.java index 2c77d601e2..91e0c57ee9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/util/table/AddressBasedTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/util/table/AddressBasedTableModel.java @@ -4,9 +4,9 @@ * 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. @@ -15,17 +15,15 @@ */ package ghidra.util.table; -import docking.widgets.table.*; -import ghidra.docking.settings.Settings; import ghidra.framework.plugintool.ServiceProvider; -import ghidra.program.model.address.Address; -import ghidra.program.model.address.AddressSet; import ghidra.program.model.listing.Program; -import ghidra.program.util.ProgramLocation; -import ghidra.program.util.ProgramSelection; -import ghidra.util.table.field.*; import ghidra.util.task.TaskMonitor; +/** + * This class is now just a shell left in place to not break external clients. + * + * @param the row type + */ public abstract class AddressBasedTableModel extends GhidraProgramTableModel { public AddressBasedTableModel(String title, ServiceProvider serviceProvider, Program program, @@ -37,100 +35,4 @@ public abstract class AddressBasedTableModel extends GhidraProgramTabl TaskMonitor monitor, boolean loadIncrementally) { super(title, serviceProvider, program, monitor, loadIncrementally); } - - public abstract Address getAddress(int row); - - @SuppressWarnings({ "unchecked", "rawtypes" }) - // We create an untyped column descriptor. However, we are assigning it to a typed variable, - // which guarantees that we only put homogeneous objects into the descriptor. - @Override - protected TableColumnDescriptor createTableColumnDescriptor() { - TableColumnDescriptor descriptor = new TableColumnDescriptor(); - - descriptor.addVisibleColumn( - DiscoverableTableUtils.adaptColumForModel(this, new AddressTableColumn()), 1, true); - descriptor.addVisibleColumn( - DiscoverableTableUtils.adaptColumForModel(this, new LabelTableColumn())); - descriptor.addVisibleColumn( - DiscoverableTableUtils.adaptColumForModel(this, new CodeUnitTableColumn())); - - return descriptor; - } - - @Override - public ProgramLocation getProgramLocation(int row, int column) { - if (row < 0 || row >= filteredData.size()) { - return null; - } - - ROW_TYPE rowObject = filteredData.get(row); - DynamicTableColumn tableColumn = getColumn(column); - if (tableColumn instanceof ProgramLocationTableColumn) { - - @SuppressWarnings("unchecked") // we checked - ProgramLocationTableColumn programField = - (ProgramLocationTableColumn) tableColumn; - ProgramLocation loc = programField.getProgramLocation(rowObject, - getColumnSettings(column), getProgram(), serviceProvider); - if (loc != null) { - return loc; - } - } - - Address address = getAddress(row, column); - if (address != null) { - return new ProgramLocation(getProgram(), address); - } - - return null; - } - - private Address getAddress(int row, int column) { - DynamicTableColumn tableColumn = getColumn(column); - - if (tableColumn instanceof ProgramLocationTableColumn) { - @SuppressWarnings("unchecked") - // we checked - ProgramLocationTableColumn programLocationColumn = - (ProgramLocationTableColumn) tableColumn; - Settings settings = getColumnSettings(column); - ROW_TYPE rowObject = filteredData.get(row); - Object value = - programLocationColumn.getValue(rowObject, settings, getProgram(), serviceProvider); - if (value instanceof Address) { - return (Address) value; - } - - if (value instanceof ProgramLocation) { - ProgramLocation programLocation = (ProgramLocation) value; - return programLocation.getByteAddress(); - } - - ProgramLocation location = programLocationColumn.getProgramLocation(rowObject, settings, - getProgram(), serviceProvider); - if (location != null) { - return location.getByteAddress(); - } - } - - ROW_TYPE storageValue = filteredData.get(row); - Object columnValueForRow = getColumnValueForRow(storageValue, column); - if (columnValueForRow instanceof Address) { - return (Address) columnValueForRow; - } - return getAddress(row); // TODO Perhaps this should return null? - } - - @Override - public ProgramSelection getProgramSelection(int[] rows) { - AddressSet addressSet = new AddressSet(); - for (int element : rows) { - Address addr = getAddress(element); - if (addr.isMemoryAddress()) { - addressSet.addRange(addr, addr); - } - } - return new ProgramSelection(addressSet); - } - } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/table/GhidraProgramTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/util/table/GhidraProgramTableModel.java index 03456993b1..bc301095ec 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/util/table/GhidraProgramTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/util/table/GhidraProgramTableModel.java @@ -4,9 +4,9 @@ * 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. @@ -15,10 +15,16 @@ */ package ghidra.util.table; +import docking.widgets.table.*; import docking.widgets.table.threaded.ThreadedTableModel; +import ghidra.docking.settings.Settings; import ghidra.framework.plugintool.ServiceProvider; import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressSet; import ghidra.program.model.listing.Program; +import ghidra.program.util.ProgramLocation; +import ghidra.program.util.ProgramSelection; +import ghidra.util.table.field.*; import ghidra.util.task.TaskMonitor; public abstract class GhidraProgramTableModel @@ -37,6 +43,23 @@ public abstract class GhidraProgramTableModel this.program = program; } + @SuppressWarnings({ "unchecked", "rawtypes" }) + // We create an untyped column descriptor. However, we are assigning it to a typed variable, + // which guarantees that we only put homogeneous objects into the descriptor. + @Override + protected TableColumnDescriptor createTableColumnDescriptor() { + TableColumnDescriptor descriptor = new TableColumnDescriptor(); + + descriptor.addVisibleColumn( + DiscoverableTableUtils.adaptColumForModel(this, new AddressTableColumn()), 1, true); + descriptor.addVisibleColumn( + DiscoverableTableUtils.adaptColumForModel(this, new LabelTableColumn())); + descriptor.addVisibleColumn( + DiscoverableTableUtils.adaptColumForModel(this, new CodeUnitTableColumn())); + + return descriptor; + } + public void setProgram(Program program) { Program originalProgram = this.program; this.program = program; @@ -66,14 +89,155 @@ public abstract class GhidraProgramTableModel return getProgram(); } - // most subclasses will override this to return an address - public Address getAddress(int row) { - return null; - } - @Override public void dispose() { program = null; super.dispose(); } + + /** + * Returns an address for the given row and column. + * @param modelRow the model row + * @param modelColumn the column row + * @return the address + */ + public Address getAddress(int modelRow, int modelColumn) { + + // + // Try to find an address for the given cell. + // + // 1) Prefer columns that have a ProgramLocation, as they are already used for navigation. + // + ROW_TYPE rowObject = filteredData.get(modelRow); + DynamicTableColumn tableColumn = getColumn(modelColumn); + if (tableColumn instanceof ProgramLocationTableColumn) { + @SuppressWarnings("unchecked") + // we checked + ProgramLocationTableColumn programLocationColumn = + (ProgramLocationTableColumn) tableColumn; + Settings settings = getColumnSettings(modelColumn); + Object value = + programLocationColumn.getValue(rowObject, settings, getProgram(), serviceProvider); + if (value instanceof Address) { + return (Address) value; + } + + if (value instanceof ProgramLocation) { + ProgramLocation programLocation = (ProgramLocation) value; + return programLocation.getByteAddress(); + } + + ProgramLocation location = programLocationColumn.getProgramLocation(rowObject, settings, + getProgram(), serviceProvider); + if (location != null) { + return location.getByteAddress(); + } + } + + // + // 2) See if the given cell value is an Address + // + Object columnValue = getColumnValueForRow(rowObject, modelColumn); + if (columnValue instanceof Address) { + return (Address) columnValue; + } + + // + // 3) Check to see if we can get an Address directly from my row object + // + Address address = getAddress(modelRow); + if (address != null) { + return address; + } + + // + // 4) Check for the case where we are using a mapped column that converted the current row + // object into an Address row object. + // + Object mappedRowObject = getMappedRowObject(tableColumn, rowObject, modelColumn); + if (mappedRowObject instanceof Address) { + return (Address) mappedRowObject; + } + + return null; + } + + /** + * Returns the best Address for the given row. + *

+ * Implementation Note: this class will only return an Address if this model's row type is + * Address. Clients that know how to get an Address for a given row should override this + * method. + * @param modelRow the row + * @return the Address or null + */ + public Address getAddress(int modelRow) { + ROW_TYPE rowObject = filteredData.get(modelRow); + if (rowObject instanceof Address) { + return (Address) rowObject; + } + return null; + } + + /** + * If the given column supports row mapping, then use that column to get the mapped row. In + * this case, our table may have a row object, like Function, that the column maps to another + * type that it needs, like Address. + * + * @param tableColumn the table column + * @param currentRowObject the table's actual non-mapped row value + * @param columnIndex the column index + * @return the mapped row value or null + */ + @SuppressWarnings("unchecked") + private Object getMappedRowObject(DynamicTableColumn tableColumn, + ROW_TYPE currentRowObject, int columnIndex) { + + if (tableColumn instanceof MappedTableColumn) { + @SuppressWarnings("rawtypes") + MappedTableColumn mappedColumn = (MappedTableColumn) tableColumn; + return mappedColumn.map(currentRowObject, getProgram(), serviceProvider); + } + return null; + } + + @Override + public ProgramLocation getProgramLocation(int modelRow, int modelColumn) { + if (modelRow < 0 || modelRow >= filteredData.size()) { + return null; + } + + ROW_TYPE rowObject = filteredData.get(modelRow); + DynamicTableColumn tableColumn = getColumn(modelColumn); + if (tableColumn instanceof ProgramLocationTableColumn) { + + @SuppressWarnings("unchecked") // we checked + ProgramLocationTableColumn programField = + (ProgramLocationTableColumn) tableColumn; + ProgramLocation loc = programField.getProgramLocation(rowObject, + getColumnSettings(modelColumn), getProgram(), serviceProvider); + if (loc != null) { + return loc; + } + } + + Address address = getAddress(modelRow, modelColumn); + if (address != null) { + return new ProgramLocation(getProgram(), address); + } + + return null; + } + + @Override + public ProgramSelection getProgramSelection(int[] modelRows) { + AddressSet addressSet = new AddressSet(); + for (int element : modelRows) { + Address addr = getAddress(element); + if (addr.isMemoryAddress()) { + addressSet.addRange(addr, addr); + } + } + return new ProgramSelection(addressSet); + } } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/GoToAddressLabelPluginTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/GoToAddressLabelPluginTest.java index 60315294a7..8cc70e7a38 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/GoToAddressLabelPluginTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/GoToAddressLabelPluginTest.java @@ -31,7 +31,6 @@ import docking.widgets.combobox.GhidraComboBox; import docking.widgets.table.GTable; import docking.widgets.table.threaded.GThreadedTablePanel; import generic.test.TestUtils; -import ghidra.GhidraOptions; import ghidra.app.cmd.data.CreateDataCmd; import ghidra.app.cmd.label.AddLabelCmd; import ghidra.app.cmd.label.CreateNamespacesCmd; @@ -570,7 +569,7 @@ public class GoToAddressLabelPluginTest extends AbstractGhidraHeadedIntegrationT public void testQueryResultsMaxHitsDynamicFound() throws Exception { loadProgram("x86"); Options opt = plugin.getTool().getOptions(SearchConstants.SEARCH_OPTION_NAME); - opt.setInt(GhidraOptions.OPTION_SEARCH_LIMIT, 20); + opt.setInt(SearchConstants.SEARCH_LIMIT_NAME, 20); setText("L*"); performOkCallback(); @@ -582,7 +581,7 @@ public class GoToAddressLabelPluginTest extends AbstractGhidraHeadedIntegrationT public void testQueryResultsMaxHitsDefinedFound() throws Exception { loadProgram("x86"); Options opt = plugin.getTool().getOptions(SearchConstants.SEARCH_OPTION_NAME); - opt.setInt(GhidraOptions.OPTION_SEARCH_LIMIT, 5); + opt.setInt(SearchConstants.SEARCH_LIMIT_NAME, 5); createLabel("1006960", "abc1"); createLabel("1006961", "abc2"); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/MappedTableColumn.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/MappedTableColumn.java index 41286fa6dd..5455b88af1 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/MappedTableColumn.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/MappedTableColumn.java @@ -4,9 +4,9 @@ * 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. @@ -124,16 +124,16 @@ public class MappedTableColumn