Minor refactor of table address retrieval and some options constants

This commit is contained in:
dragonmacher 2024-10-25 17:41:31 -04:00
parent 7ddd8665b7
commit 5d58d61506
15 changed files with 301 additions and 196 deletions

View File

@ -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.

View File

@ -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<AddressRangeInfo> {
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<AddressRange
this.minLength = minLength;
}
@Override
public ProgramLocation getProgramLocation(int modelRow, int modelColumn) {
AddressRangeInfo rangeInfo = getRowObject(modelRow);
if (modelColumn == MAX_ADDRESS_COLUMN_INDEX) {
return new ProgramLocation(program, rangeInfo.max());
}
return new ProgramLocation(program, rangeInfo.min());
}
@Override
public ProgramSelection getProgramSelection(int[] modelRows) {
AddressSet ranges = new AddressSet();
for (AddressRangeInfo rangeInfo : getRowObjects(modelRows)) {
ranges.addRange(program, rangeInfo.min(), rangeInfo.max());
}
return new ProgramSelection(program.getAddressFactory(), ranges);
}
@Override
protected void doLoad(Accumulator<AddressRangeInfo> accumulator, TaskMonitor monitor)
throws CancelledException {
@ -140,6 +124,42 @@ public class AddressRangeTableModel extends GhidraProgramTableModel<AddressRange
return descriptor;
}
@Override
public ProgramLocation getProgramLocation(int modelRow, int modelColumn) {
AddressRangeInfo rangeInfo = getRowObject(modelRow);
if (modelColumn == MAX_ADDRESS_COLUMN_INDEX) {
return new ProgramLocation(program, rangeInfo.max());
}
return new ProgramLocation(program, rangeInfo.min());
}
@Override
public ProgramSelection getProgramSelection(int[] modelRows) {
AddressSet ranges = new AddressSet();
for (AddressRangeInfo rangeInfo : getRowObjects(modelRows)) {
ranges.addRange(program, rangeInfo.min(), rangeInfo.max());
}
return new ProgramSelection(ranges);
}
@Override
public Address getAddress(int modelRow) {
AddressRangeInfo rangeInfo = getRowObject(modelRow);
return rangeInfo.min();
}
@Override
public Address getAddress(int modelRow, int modelColumn) {
AddressRangeInfo rangeInfo = getRowObject(modelRow);
if (modelColumn == MIN_ADDRESS_COLUMN_INDEX) {
return rangeInfo.min();
}
else if (modelColumn == MAX_ADDRESS_COLUMN_INDEX) {
return rangeInfo.max();
}
return null;
}
private class MinAddressTableColumn
extends AbstractDynamicTableColumn<AddressRangeInfo, Address, Object> {
@ -235,20 +255,19 @@ public class AddressRangeTableModel extends GhidraProgramTableModel<AddressRange
}
}
private class NumRefsFromTableColumn
extends AbstractDynamicTableColumn<AddressRangeInfo, Integer, Object> {
private class NumRefsFromTableColumn
extends AbstractDynamicTableColumn<AddressRangeInfo, Integer, Object> {
@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();
}
}
}

View File

@ -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;
}

View File

@ -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 =

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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.
*/

View File

@ -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;
}

View File

@ -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);

View File

@ -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 <ROW_TYPE> the row type
*/
public abstract class AddressBasedTableModel<ROW_TYPE> extends GhidraProgramTableModel<ROW_TYPE> {
public AddressBasedTableModel(String title, ServiceProvider serviceProvider, Program program,
@ -37,100 +35,4 @@ public abstract class AddressBasedTableModel<ROW_TYPE> 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<ROW_TYPE> createTableColumnDescriptor() {
TableColumnDescriptor<ROW_TYPE> 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<ROW_TYPE, ?, ?> tableColumn = getColumn(column);
if (tableColumn instanceof ProgramLocationTableColumn<?, ?>) {
@SuppressWarnings("unchecked") // we checked
ProgramLocationTableColumn<ROW_TYPE, ?> programField =
(ProgramLocationTableColumn<ROW_TYPE, ?>) 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<ROW_TYPE, ?, ?> tableColumn = getColumn(column);
if (tableColumn instanceof ProgramLocationTableColumn<?, ?>) {
@SuppressWarnings("unchecked")
// we checked
ProgramLocationTableColumn<ROW_TYPE, ?> programLocationColumn =
(ProgramLocationTableColumn<ROW_TYPE, ?>) 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);
}
}

View File

@ -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<ROW_TYPE>
@ -37,6 +43,23 @@ public abstract class GhidraProgramTableModel<ROW_TYPE>
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<ROW_TYPE> createTableColumnDescriptor() {
TableColumnDescriptor<ROW_TYPE> 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<ROW_TYPE>
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<ROW_TYPE, ?, ?> tableColumn = getColumn(modelColumn);
if (tableColumn instanceof ProgramLocationTableColumn<?, ?>) {
@SuppressWarnings("unchecked")
// we checked
ProgramLocationTableColumn<ROW_TYPE, ?> programLocationColumn =
(ProgramLocationTableColumn<ROW_TYPE, ?>) 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.
* <P>
* 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<ROW_TYPE, ?, ?> 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<ROW_TYPE, ?, ?> tableColumn = getColumn(modelColumn);
if (tableColumn instanceof ProgramLocationTableColumn<?, ?>) {
@SuppressWarnings("unchecked") // we checked
ProgramLocationTableColumn<ROW_TYPE, ?> programField =
(ProgramLocationTableColumn<ROW_TYPE, ?>) 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);
}
}

View File

@ -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");

View File

@ -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<ROW_TYPE, EXPECTED_ROW_TYPE, COLUMN_TYPE, DATA_SO
public COLUMN_TYPE getValue(ROW_TYPE rowObject, Settings settings, DATA_SOURCE data,
ServiceProvider serviceProvider) throws IllegalArgumentException {
if (rowObject == null) {
// can happen when the model is cleared out from under Swing
return null;
}
EXPECTED_ROW_TYPE mappedRowObject = map(rowObject, data, serviceProvider);
return tableColumn.getValue(mappedRowObject, settings, data, serviceProvider);
}
EXPECTED_ROW_TYPE mappedObject = mapper.map(rowObject, data, serviceProvider);
if (mappedObject == null) {
return null; // some mappers have null data
public EXPECTED_ROW_TYPE map(ROW_TYPE rowObject, DATA_SOURCE data,
ServiceProvider serviceProvider) {
if (rowObject == null) {
return null;// can happen when the model is cleared out from under Swing
}
return tableColumn.getValue(mappedObject, settings, data, serviceProvider);
return mapper.map(rowObject, data, serviceProvider);
}
@Override

View File

@ -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.
@ -27,10 +27,10 @@ import docking.ComponentProvider;
import docking.DialogComponentProvider;
import docking.widgets.combobox.GhidraComboBox;
import docking.widgets.table.threaded.ThreadedTableModel;
import ghidra.GhidraOptions;
import ghidra.app.plugin.core.searchtext.SearchTextPlugin;
import ghidra.app.plugin.core.string.StringTableProvider;
import ghidra.app.plugin.core.table.TableComponentProvider;
import ghidra.app.util.SearchConstants;
/**
* Captures screenshots associated with Memory Search.
@ -160,7 +160,7 @@ public class SearchScreenShots extends AbstractSearchScreenShots {
// custom program we've loaded. Also, we are NOT changing the option so that dialog
// that is shown will have the default value
searchPlugin = env.getPlugin(SearchTextPlugin.class);
searchPlugin.optionsChanged(null, GhidraOptions.OPTION_SEARCH_LIMIT, null, 10);
searchPlugin.optionsChanged(null, SearchConstants.SEARCH_LIMIT_NAME, null, 10);
performAction("Search Text", "SearchTextPlugin", false);
waitForSwing();