mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
GP-1514 - Find References to - Added support for finding usage of enum
fields Closes #1967
This commit is contained in:
parent
2fb860bcd7
commit
33b2bbbd0b
15 changed files with 108 additions and 135 deletions
|
@ -27,7 +27,6 @@ import ghidra.app.plugin.core.navigation.FindAppliedDataTypesService;
|
||||||
import ghidra.app.plugin.core.navigation.locationreferences.ReferenceUtils;
|
import ghidra.app.plugin.core.navigation.locationreferences.ReferenceUtils;
|
||||||
import ghidra.app.util.HelpTopics;
|
import ghidra.app.util.HelpTopics;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.program.model.data.Composite;
|
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
|
|
||||||
|
@ -56,7 +55,7 @@ public abstract class AbstractFindReferencesDataTypeAction extends DockingAction
|
||||||
|
|
||||||
protected abstract DataType getDataType(ActionContext context);
|
protected abstract DataType getDataType(ActionContext context);
|
||||||
|
|
||||||
protected String getDataTypeField() {
|
protected String getDataTypeField(DataType baseDataType) {
|
||||||
// The base implementation only searches for references to the data type, not specific
|
// The base implementation only searches for references to the data type, not specific
|
||||||
// fields. Subclasses can change this behavior
|
// fields. Subclasses can change this behavior
|
||||||
return null;
|
return null;
|
||||||
|
@ -89,23 +88,8 @@ public abstract class AbstractFindReferencesDataTypeAction extends DockingAction
|
||||||
|
|
||||||
DataType dataType = getDataType(context);
|
DataType dataType = getDataType(context);
|
||||||
DataType baseDataType = ReferenceUtils.getBaseDataType(dataType);
|
DataType baseDataType = ReferenceUtils.getBaseDataType(dataType);
|
||||||
String field = getDataTypeField();
|
String field = getDataTypeField(baseDataType);
|
||||||
|
Swing.runLater(() -> service.findAndDisplayAppliedDataTypeAddresses(baseDataType, field));
|
||||||
// sanity check - should not happen
|
|
||||||
if (field != null && !(baseDataType instanceof Composite)) {
|
|
||||||
Msg.error(this, "Somehow have a field without a Composite parent--searching " +
|
|
||||||
"only for the parent type '" + dataType + "'; field '" + field + "'");
|
|
||||||
Swing.runLater(() -> service.findAndDisplayAppliedDataTypeAddresses(dataType));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (field == null) {
|
|
||||||
Swing.runLater(() -> service.findAndDisplayAppliedDataTypeAddresses(dataType));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Swing.runLater(() -> service.findAndDisplayAppliedDataTypeAddresses(
|
|
||||||
(Composite) baseDataType, field));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ package ghidra.app.plugin.core.datamgr.actions;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
import javax.swing.tree.TreePath;
|
import javax.swing.tree.TreePath;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
@ -35,8 +34,8 @@ import ghidra.app.plugin.core.datamgr.tree.DataTypeNode;
|
||||||
import ghidra.app.plugin.core.navigation.FindAppliedDataTypesService;
|
import ghidra.app.plugin.core.navigation.FindAppliedDataTypesService;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.program.model.data.Enum;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.*;
|
||||||
|
|
||||||
public class FindReferencesToFieldAction extends DockingAction {
|
public class FindReferencesToFieldAction extends DockingAction {
|
||||||
|
|
||||||
|
@ -72,7 +71,7 @@ public class FindReferencesToFieldAction extends DockingAction {
|
||||||
}
|
}
|
||||||
DataTypeNode dtNode = (DataTypeNode) node;
|
DataTypeNode dtNode = (DataTypeNode) node;
|
||||||
DataType dataType = dtNode.getDataType();
|
DataType dataType = dtNode.getDataType();
|
||||||
return dataType instanceof Composite;
|
return dataType instanceof Composite || dataType instanceof Enum;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -83,7 +82,6 @@ public class FindReferencesToFieldAction extends DockingAction {
|
||||||
|
|
||||||
PluginTool tool = plugin.getTool();
|
PluginTool tool = plugin.getTool();
|
||||||
FindAppliedDataTypesService service = tool.getService(FindAppliedDataTypesService.class);
|
FindAppliedDataTypesService service = tool.getService(FindAppliedDataTypesService.class);
|
||||||
|
|
||||||
if (service == null) {
|
if (service == null) {
|
||||||
Msg.showError(this, null, "Missing Plugin",
|
Msg.showError(this, null, "Missing Plugin",
|
||||||
"The FindAppliedDataTypesService is not installed.\n" +
|
"The FindAppliedDataTypesService is not installed.\n" +
|
||||||
|
@ -91,7 +89,27 @@ public class FindReferencesToFieldAction extends DockingAction {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Composite composite = (Composite) dataTypeNode.getDataType();
|
DataType dt = dataTypeNode.getDataType();
|
||||||
|
String[] choices = null;
|
||||||
|
if (dt instanceof Composite) {
|
||||||
|
choices = getCompisiteFieldNames((Composite) dt);
|
||||||
|
}
|
||||||
|
else if (dt instanceof Enum) {
|
||||||
|
choices = ((Enum) dt).getNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
String userChoice = OptionDialog.showInputChoiceDialog(null, "Choose Field",
|
||||||
|
"Find uses of '" + dt.getName() + "' field", choices, null,
|
||||||
|
OptionDialog.QUESTION_MESSAGE);
|
||||||
|
if (userChoice == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Swing.runLater(
|
||||||
|
() -> service.findAndDisplayAppliedDataTypeAddresses(dt, userChoice));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] getCompisiteFieldNames(Composite composite) {
|
||||||
DataTypeComponent[] components = composite.getDefinedComponents();
|
DataTypeComponent[] components = composite.getDefinedComponents();
|
||||||
List<String> names = new ArrayList<>();
|
List<String> names = new ArrayList<>();
|
||||||
for (DataTypeComponent dataTypeComponent : components) {
|
for (DataTypeComponent dataTypeComponent : components) {
|
||||||
|
@ -105,17 +123,7 @@ public class FindReferencesToFieldAction extends DockingAction {
|
||||||
names.add(fieldName);
|
names.add(fieldName);
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] array = names.toArray(new String[names.size()]);
|
return names.toArray(String[]::new);
|
||||||
String userChoice = OptionDialog.showInputChoiceDialog(null, "Choose Field",
|
|
||||||
"Find uses of '" + composite.getName() + "' field", array, null,
|
|
||||||
OptionDialog.QUESTION_MESSAGE);
|
|
||||||
|
|
||||||
if (userChoice == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SwingUtilities.invokeLater(
|
|
||||||
() -> service.findAndDisplayAppliedDataTypeAddresses(composite, userChoice));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.navigation;
|
package ghidra.app.plugin.core.navigation;
|
||||||
|
|
||||||
import ghidra.program.model.data.Composite;
|
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,7 +23,7 @@ import ghidra.program.model.data.DataType;
|
||||||
public interface FindAppliedDataTypesService {
|
public interface FindAppliedDataTypesService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells this service to find all places where the given datatype is defined <b>and</b> will
|
* Tells this service to find all places where the given datatype is applied <b>and</b> will
|
||||||
* display the results of the search.
|
* display the results of the search.
|
||||||
*
|
*
|
||||||
* @param dataType The datatype which to base the search upon.
|
* @param dataType The datatype which to base the search upon.
|
||||||
|
@ -32,11 +31,11 @@ public interface FindAppliedDataTypesService {
|
||||||
public void findAndDisplayAppliedDataTypeAddresses(DataType dataType);
|
public void findAndDisplayAppliedDataTypeAddresses(DataType dataType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells this service to find all places where the given datatype is defined <b>and</b> will
|
* Tells this service to find all places where the given datatype is applied <b>and</b> will
|
||||||
* display the results of the search.
|
* display the results of the search.
|
||||||
*
|
*
|
||||||
* @param dataType The datatype which to base the search upon.
|
* @param dataType The datatype which to base the search upon.
|
||||||
* @param fieldName the sub-field for which to search
|
* @param fieldName the sub-field for which to search
|
||||||
*/
|
*/
|
||||||
public void findAndDisplayAppliedDataTypeAddresses(Composite dataType, String fieldName);
|
public void findAndDisplayAppliedDataTypeAddresses(DataType dataType, String fieldName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ import org.apache.commons.lang3.StringUtils;
|
||||||
import docking.widgets.fieldpanel.support.Highlight;
|
import docking.widgets.fieldpanel.support.Highlight;
|
||||||
import ghidra.app.util.viewer.field.*;
|
import ghidra.app.util.viewer.field.*;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.data.Composite;
|
|
||||||
import ghidra.program.model.listing.Data;
|
import ghidra.program.model.listing.Data;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.util.datastruct.Accumulator;
|
import ghidra.util.datastruct.Accumulator;
|
||||||
|
@ -30,8 +29,8 @@ import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A data type location descriptor that allows you to represent a location for a member field of
|
* A data type location descriptor that allows you to represent a location for a member field of a
|
||||||
* a composite.
|
* data type, such as a composite or an enum
|
||||||
*/
|
*/
|
||||||
public class GenericCompositeDataTypeLocationDescriptor extends GenericDataTypeLocationDescriptor {
|
public class GenericCompositeDataTypeLocationDescriptor extends GenericDataTypeLocationDescriptor {
|
||||||
|
|
||||||
|
@ -50,9 +49,7 @@ public class GenericCompositeDataTypeLocationDescriptor extends GenericDataTypeL
|
||||||
@Override
|
@Override
|
||||||
protected void doGetReferences(Accumulator<LocationReference> accumulator, TaskMonitor monitor)
|
protected void doGetReferences(Accumulator<LocationReference> accumulator, TaskMonitor monitor)
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
|
ReferenceUtils.findDataTypeReferences(accumulator, getDataType(), fieldName, program,
|
||||||
Composite currentDataType = (Composite) getDataType();
|
|
||||||
ReferenceUtils.findDataTypeReferences(accumulator, currentDataType, fieldName, program,
|
|
||||||
useDynamicSearching, monitor);
|
useDynamicSearching, monitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,13 +99,13 @@ public class GenericCompositeDataTypeLocationDescriptor extends GenericDataTypeL
|
||||||
// the parent's name and not the field's name.
|
// the parent's name and not the field's name.
|
||||||
}
|
}
|
||||||
else if (LabelFieldFactory.class.isAssignableFrom(fieldFactoryClass)) {
|
else if (LabelFieldFactory.class.isAssignableFrom(fieldFactoryClass)) {
|
||||||
// It would be nice to highlight the label that points into data structures.
|
// It would be nice to highlight the label that points into data structures.
|
||||||
// However, the label is on the parent address, which is not in our list of matches
|
// However, the label is on the parent address, which is not in our list of matches
|
||||||
// when we are offcut. Further, using the program to lookup each address that
|
// when we are offcut. Further, using the program to lookup each address that
|
||||||
// comes in to see if it is our paren't address seems too expensive, as highlighting
|
// comes in to see if it is our paren't address seems too expensive, as highlighting
|
||||||
// code is called for every paint operation.
|
// code is called for every paint operation.
|
||||||
//
|
//
|
||||||
// We could add the parent match to the list of known addresses and then use that
|
// We could add the parent match to the list of known addresses and then use that
|
||||||
// to lookup in real-time later. To do this we would need the current list of
|
// to lookup in real-time later. To do this we would need the current list of
|
||||||
// reference addresses and a new list of parent data addresses. That seems a bit
|
// reference addresses and a new list of parent data addresses. That seems a bit
|
||||||
// involved just for highlighting a label.
|
// involved just for highlighting a label.
|
||||||
|
|
|
@ -18,12 +18,13 @@ package ghidra.app.plugin.core.navigation.locationreferences;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import ghidra.program.model.data.Composite;
|
import ghidra.program.model.data.Composite;
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class to signal that the ProgramLocation is used for data types and is not really
|
* A class to signal that the ProgramLocation is used for data types and is not really
|
||||||
* connected to the listing. This is a subclass specifically for {@link Composite} types and a
|
* connected to the listing. This is a subclass is designed for data types that have fields, such
|
||||||
* particular field name of the given composite.
|
* as {@link Composite} types and {@link Enum} types.
|
||||||
*
|
*
|
||||||
* @see GenericCompositeDataTypeLocationDescriptor
|
* @see GenericCompositeDataTypeLocationDescriptor
|
||||||
*/
|
*/
|
||||||
|
@ -31,7 +32,7 @@ public class GenericCompositeDataTypeProgramLocation extends GenericDataTypeProg
|
||||||
|
|
||||||
private String fieldName;
|
private String fieldName;
|
||||||
|
|
||||||
GenericCompositeDataTypeProgramLocation(Program program, Composite dataType, String fieldName) {
|
GenericCompositeDataTypeProgramLocation(Program program, DataType dataType, String fieldName) {
|
||||||
super(program, dataType);
|
super(program, dataType);
|
||||||
this.fieldName = Objects.requireNonNull(fieldName);
|
this.fieldName = Objects.requireNonNull(fieldName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,6 @@ import ghidra.app.util.query.TableService;
|
||||||
import ghidra.framework.options.ToolOptions;
|
import ghidra.framework.options.ToolOptions;
|
||||||
import ghidra.framework.plugintool.*;
|
import ghidra.framework.plugintool.*;
|
||||||
import ghidra.framework.plugintool.util.PluginStatus;
|
import ghidra.framework.plugintool.util.PluginStatus;
|
||||||
import ghidra.program.model.data.Composite;
|
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.symbol.Reference;
|
import ghidra.program.model.symbol.Reference;
|
||||||
|
@ -102,10 +101,10 @@ public class LocationReferencesPlugin extends Plugin
|
||||||
tool.addAction(referencesToAddressAction);
|
tool.addAction(referencesToAddressAction);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Unusual Code: This plugin does not use the delete action directly, but our transient
|
// Unusual Code: This plugin does not use the delete action directly, but our transient
|
||||||
// tables do. We need a way to have keybindings shared for this action.
|
// tables do. We need a way to have keybindings shared for this action.
|
||||||
// Further, we need to register it now, not when the transient
|
// Further, we need to register it now, not when the transient
|
||||||
// providers are created, as they would only appear in the options at
|
// providers are created, as they would only appear in the options at
|
||||||
// that point.
|
// that point.
|
||||||
//
|
//
|
||||||
DeleteTableRowAction.registerDummy(tool, getName());
|
DeleteTableRowAction.registerDummy(tool, getName());
|
||||||
|
@ -173,7 +172,7 @@ public class LocationReferencesPlugin extends Plugin
|
||||||
|
|
||||||
tool.showComponentProvider(provider, true);
|
tool.showComponentProvider(provider, true);
|
||||||
|
|
||||||
// REFS: is the following statement true???...it seems that the loading is off the swing thread,
|
// REFS: is the following statement true???...it seems that the loading is off the swing thread,
|
||||||
// so it still may not be done at this point!
|
// so it still may not be done at this point!
|
||||||
|
|
||||||
// we add the provider here instead of where it is created above to allow the provider to
|
// we add the provider here instead of where it is created above to allow the provider to
|
||||||
|
@ -311,7 +310,7 @@ public class LocationReferencesPlugin extends Plugin
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void findAndDisplayAppliedDataTypeAddresses(Composite dataType, String fieldName) {
|
public void findAndDisplayAppliedDataTypeAddresses(DataType dataType, String fieldName) {
|
||||||
ProgramManager programManagerService = tool.getService(ProgramManager.class);
|
ProgramManager programManagerService = tool.getService(ProgramManager.class);
|
||||||
GoToService goToService = tool.getService(GoToService.class);
|
GoToService goToService = tool.getService(GoToService.class);
|
||||||
Program program = programManagerService.getCurrentProgram();
|
Program program = programManagerService.getCurrentProgram();
|
||||||
|
|
|
@ -31,7 +31,6 @@ import ghidra.program.util.*;
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
import ghidra.util.classfinder.ClassSearcher;
|
import ghidra.util.classfinder.ClassSearcher;
|
||||||
import ghidra.util.datastruct.*;
|
import ghidra.util.datastruct.*;
|
||||||
import ghidra.util.exception.AssertException;
|
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
|
@ -210,11 +209,6 @@ public final class ReferenceUtils {
|
||||||
// Note: none of the params can be null, but this one gets used much later, so check now
|
// Note: none of the params can be null, but this one gets used much later, so check now
|
||||||
Objects.requireNonNull(dataType, () -> "Data Type cannot be null");
|
Objects.requireNonNull(dataType, () -> "Data Type cannot be null");
|
||||||
|
|
||||||
// sanity check
|
|
||||||
if (fieldName != null && !(dataType instanceof Composite)) {
|
|
||||||
throw new IllegalArgumentException("Can only search for a field with a Composite type");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (monitor == null) {
|
if (monitor == null) {
|
||||||
monitor = TaskMonitor.DUMMY;
|
monitor = TaskMonitor.DUMMY;
|
||||||
}
|
}
|
||||||
|
@ -283,12 +277,6 @@ public final class ReferenceUtils {
|
||||||
accumulator.add(locationReference);
|
accumulator.add(locationReference);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (fieldName != null && !(dataType instanceof Composite)) {
|
|
||||||
throw new AssertException(
|
|
||||||
"Must have a Composite data type to perform a field search. Found " + dataType +
|
|
||||||
"; field '" + fieldName + "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (finders.isEmpty()) {
|
if (finders.isEmpty()) {
|
||||||
Msg.debug(ReferenceUtils.class, "Unable to find any implementations of " +
|
Msg.debug(ReferenceUtils.class, "Unable to find any implementations of " +
|
||||||
DataTypeReferenceFinder.class.getSimpleName());
|
DataTypeReferenceFinder.class.getSimpleName());
|
||||||
|
@ -300,7 +288,7 @@ public final class ReferenceUtils {
|
||||||
finder.findReferences(program, dataType, callback, monitor);
|
finder.findReferences(program, dataType, callback, monitor);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
finder.findReferences(program, (Composite) dataType, fieldName, callback, monitor);
|
finder.findReferences(program, dataType, fieldName, callback, monitor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ public class DataTypeReference {
|
||||||
fieldNameText +
|
fieldNameText +
|
||||||
"\tfunction: " + function.getName() + "\n" +
|
"\tfunction: " + function.getName() + "\n" +
|
||||||
"\taddress: " + address + "\n" +
|
"\taddress: " + address + "\n" +
|
||||||
"\tcontext: " + context + "\n" +
|
"\tcontext: " + context.getPlainText() + "\n" +
|
||||||
"}";
|
"}";
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,10 +33,10 @@ import ghidra.util.task.TaskMonitor;
|
||||||
public interface DataTypeReferenceFinder extends ExtensionPoint {
|
public interface DataTypeReferenceFinder extends ExtensionPoint {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds references in the current program in a manner appropriate with the given
|
* Finds references in the current program in a manner appropriate with the given
|
||||||
* implementation.
|
* implementation.
|
||||||
* <p>
|
* <p>
|
||||||
* Note that this operation is multi-threaded and that results will be delivered as they
|
* Note that this operation is multi-threaded and that results will be delivered as they
|
||||||
* are found via the <code>callback</code>.
|
* are found via the <code>callback</code>.
|
||||||
*
|
*
|
||||||
* @param program the program to search
|
* @param program the program to search
|
||||||
|
@ -53,16 +53,16 @@ public interface DataTypeReferenceFinder extends ExtensionPoint {
|
||||||
* Finds references in the current program to specific field of the given {@link Composite} type
|
* Finds references in the current program to specific field of the given {@link Composite} type
|
||||||
* in a manner appropriate with the given implementation.
|
* in a manner appropriate with the given implementation.
|
||||||
* <p>
|
* <p>
|
||||||
* Note that this operation is multi-threaded and that results will be delivered as they
|
* Note that this operation is multi-threaded and that results will be delivered as they
|
||||||
* are found via the <code>callback</code>.
|
* are found via the <code>callback</code>.
|
||||||
*
|
*
|
||||||
* @param program the program to search
|
* @param program the program to search
|
||||||
* @param composite the type containing the field for which to search
|
* @param dataType the type containing the field for which to search
|
||||||
* @param fieldName the name of the composite's field for which to search
|
* @param fieldName the name of the composite's field for which to search
|
||||||
* @param callback the callback to be called when a reference is found
|
* @param callback the callback to be called when a reference is found
|
||||||
* @param monitor the monitor that allows for progress and cancellation
|
* @param monitor the monitor that allows for progress and cancellation
|
||||||
* @throws CancelledException if the operation was cancelled
|
* @throws CancelledException if the operation was cancelled
|
||||||
*/
|
*/
|
||||||
public void findReferences(Program program, Composite composite, String fieldName,
|
public void findReferences(Program program, DataType dataType, String fieldName,
|
||||||
Consumer<DataTypeReference> callback, TaskMonitor monitor) throws CancelledException;
|
Consumer<DataTypeReference> callback, TaskMonitor monitor) throws CancelledException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,14 +18,14 @@ package ghidra.app.plugin.core.decompile.actions;
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
import docking.action.MenuData;
|
import docking.action.MenuData;
|
||||||
import ghidra.app.actions.AbstractFindReferencesDataTypeAction;
|
import ghidra.app.actions.AbstractFindReferencesDataTypeAction;
|
||||||
import ghidra.app.decompiler.ClangFieldToken;
|
import ghidra.app.decompiler.*;
|
||||||
import ghidra.app.decompiler.ClangToken;
|
|
||||||
import ghidra.app.decompiler.component.*;
|
import ghidra.app.decompiler.component.*;
|
||||||
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
||||||
import ghidra.app.plugin.core.navigation.locationreferences.LocationReferencesService;
|
import ghidra.app.plugin.core.navigation.locationreferences.LocationReferencesService;
|
||||||
import ghidra.app.util.HelpTopics;
|
import ghidra.app.util.HelpTopics;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
|
import ghidra.program.model.data.Enum;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
public class FindReferencesToDataTypeAction extends AbstractFindReferencesDataTypeAction {
|
public class FindReferencesToDataTypeAction extends AbstractFindReferencesDataTypeAction {
|
||||||
|
@ -44,12 +44,11 @@ public class FindReferencesToDataTypeAction extends AbstractFindReferencesDataTy
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataType getDataType(ActionContext context) {
|
public DataType getDataType(ActionContext context) {
|
||||||
|
|
||||||
return DecompilerUtils.getDataType((DecompilerActionContext) context);
|
return DecompilerUtils.getDataType((DecompilerActionContext) context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getDataTypeField() {
|
protected String getDataTypeField(DataType dataType) {
|
||||||
|
|
||||||
DecompilerPanel decompilerPanel = controller.getDecompilerPanel();
|
DecompilerPanel decompilerPanel = controller.getDecompilerPanel();
|
||||||
ClangToken tokenAtCursor = decompilerPanel.getTokenAtCursor();
|
ClangToken tokenAtCursor = decompilerPanel.getTokenAtCursor();
|
||||||
|
@ -57,6 +56,20 @@ public class FindReferencesToDataTypeAction extends AbstractFindReferencesDataTy
|
||||||
return tokenAtCursor.getText();
|
return tokenAtCursor.getText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dataType instanceof Enum) {
|
||||||
|
|
||||||
|
// check for enum field
|
||||||
|
ClangVariableToken vt = (ClangVariableToken) tokenAtCursor;
|
||||||
|
String text = vt.getText();
|
||||||
|
Enum e = (Enum) dataType;
|
||||||
|
String[] names = e.getNames();
|
||||||
|
for (String name : names) {
|
||||||
|
if (name.equals(text)) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,8 +106,7 @@ public class FindReferencesToDataTypeAction extends AbstractFindReferencesDataTy
|
||||||
|
|
||||||
String typeName = type.getName();
|
String typeName = type.getName();
|
||||||
String menuName = "Find Uses of " + typeName;
|
String menuName = "Find Uses of " + typeName;
|
||||||
|
String fieldName = getDataTypeField(type);
|
||||||
String fieldName = getDataTypeField();
|
|
||||||
if (fieldName != null) {
|
if (fieldName != null) {
|
||||||
menuName += '.' + fieldName;
|
menuName += '.' + fieldName;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,6 @@ import ghidra.app.plugin.core.navigation.locationreferences.LocationReferencesPr
|
||||||
import ghidra.app.plugin.core.navigation.locationreferences.LocationReferencesService;
|
import ghidra.app.plugin.core.navigation.locationreferences.LocationReferencesService;
|
||||||
import ghidra.app.services.DataTypeReference;
|
import ghidra.app.services.DataTypeReference;
|
||||||
import ghidra.app.services.DataTypeReferenceFinder;
|
import ghidra.app.services.DataTypeReferenceFinder;
|
||||||
import ghidra.program.model.data.Composite;
|
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
|
@ -167,7 +166,7 @@ public abstract class AbstractDecompilerFindReferencesActionTest extends Abstrac
|
||||||
}
|
}
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
public void findReferences(Program p, Composite composite, String fieldName,
|
public void findReferences(Program p, DataType dt, String fieldName,
|
||||||
Consumer<DataTypeReference> callback, TaskMonitor monitor) {
|
Consumer<DataTypeReference> callback, TaskMonitor monitor) {
|
||||||
|
|
||||||
compositeFieldReferencesCallCount.incrementAndGet();
|
compositeFieldReferencesCallCount.incrementAndGet();
|
||||||
|
|
|
@ -19,7 +19,6 @@ import java.util.function.Consumer;
|
||||||
|
|
||||||
import ghidra.app.services.DataTypeReference;
|
import ghidra.app.services.DataTypeReference;
|
||||||
import ghidra.app.services.DataTypeReferenceFinder;
|
import ghidra.app.services.DataTypeReferenceFinder;
|
||||||
import ghidra.program.model.data.Composite;
|
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
@ -37,7 +36,7 @@ public class StubDataTypeReferenceFinder implements DataTypeReferenceFinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void findReferences(Program program, Composite composite, String fieldName,
|
public void findReferences(Program program, DataType dataType, String fieldName,
|
||||||
Consumer<DataTypeReference> callback, TaskMonitor monitor) throws CancelledException {
|
Consumer<DataTypeReference> callback, TaskMonitor monitor) throws CancelledException {
|
||||||
// stub
|
// stub
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,8 @@ import ghidra.app.plugin.core.navigation.locationreferences.ReferenceUtils;
|
||||||
import ghidra.app.services.DataTypeReference;
|
import ghidra.app.services.DataTypeReference;
|
||||||
import ghidra.app.services.DataTypeReferenceFinder;
|
import ghidra.app.services.DataTypeReferenceFinder;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.BuiltInDataType;
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.StringUtilities;
|
import ghidra.util.StringUtilities;
|
||||||
|
@ -40,7 +41,7 @@ import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of {@link DataTypeReferenceFinder} that uses the Decompiler's output
|
* Implementation of {@link DataTypeReferenceFinder} that uses the Decompiler's output
|
||||||
* to find data type and composite field usage.
|
* to find data type and composite field usage.
|
||||||
*/
|
*/
|
||||||
public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinder {
|
public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinder {
|
||||||
|
@ -52,29 +53,11 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
||||||
@Override
|
@Override
|
||||||
public void findReferences(Program program, DataType dataType,
|
public void findReferences(Program program, DataType dataType,
|
||||||
Consumer<DataTypeReference> callback, TaskMonitor monitor) throws CancelledException {
|
Consumer<DataTypeReference> callback, TaskMonitor monitor) throws CancelledException {
|
||||||
|
findReferences(program, dataType, null, callback, monitor);
|
||||||
DecompilerDataTypeFinderQCallback qCallback =
|
|
||||||
new DecompilerDataTypeFinderQCallback(program, dataType, callback);
|
|
||||||
|
|
||||||
Set<Function> functions = filterFunctions(program, dataType, monitor);
|
|
||||||
|
|
||||||
try {
|
|
||||||
ParallelDecompiler.decompileFunctions(qCallback, functions, monitor);
|
|
||||||
}
|
|
||||||
catch (InterruptedException e) {
|
|
||||||
Thread.currentThread().interrupt(); // reset the flag
|
|
||||||
Msg.trace(this, "Interrupted while decompiling functions");
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
Msg.error(this, "Encountered an exception decompiling functions", e);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
qCallback.dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void findReferences(Program program, Composite dataType, String fieldName,
|
public void findReferences(Program program, DataType dataType, String fieldName,
|
||||||
Consumer<DataTypeReference> callback, TaskMonitor monitor) throws CancelledException {
|
Consumer<DataTypeReference> callback, TaskMonitor monitor) throws CancelledException {
|
||||||
|
|
||||||
DecompilerDataTypeFinderQCallback qCallback =
|
DecompilerDataTypeFinderQCallback qCallback =
|
||||||
|
@ -175,12 +158,12 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
||||||
|
|
||||||
// We have a different type, should we search for it?
|
// We have a different type, should we search for it?
|
||||||
if (baseType instanceof BuiltInDataType) {
|
if (baseType instanceof BuiltInDataType) {
|
||||||
// When given a wrapper type (e.g., typedef) , ignore
|
// When given a wrapper type (e.g., typedef) , ignore
|
||||||
// built-ins (e.g., int, byte, etc), as
|
// built-ins (e.g., int, byte, etc), as
|
||||||
// they will be of little value due to their volume in the program and the
|
// they will be of little value due to their volume in the program and the
|
||||||
// user *probably* did not intend to search for them. (Below we do not do
|
// user *probably* did not intend to search for them. (Below we do not do
|
||||||
// this check, which allows the user to search directly for a
|
// this check, which allows the user to search directly for a
|
||||||
// built-in type, if they wish.)
|
// built-in type, if they wish.)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,12 +210,6 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
||||||
private DataType dataType;
|
private DataType dataType;
|
||||||
private String fieldName;
|
private String fieldName;
|
||||||
|
|
||||||
/* Search for Data Type access only--no field usage */
|
|
||||||
DecompilerDataTypeFinderQCallback(Program program, DataType dataType,
|
|
||||||
Consumer<DataTypeReference> callback) {
|
|
||||||
this(program, dataType, null, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Search for composite field access */
|
/* Search for composite field access */
|
||||||
DecompilerDataTypeFinderQCallback(Program program, DataType dataType, String fieldName,
|
DecompilerDataTypeFinderQCallback(Program program, DataType dataType, String fieldName,
|
||||||
Consumer<DataTypeReference> callback) {
|
Consumer<DataTypeReference> callback) {
|
||||||
|
@ -279,7 +256,7 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to do the work of searching through the Decompiler's results for the desired
|
* Class to do the work of searching through the Decompiler's results for the desired
|
||||||
* data type access.
|
* data type access.
|
||||||
*/
|
*/
|
||||||
private static class DecompilerDataTypeFinder {
|
private static class DecompilerDataTypeFinder {
|
||||||
|
@ -308,7 +285,7 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
||||||
|
|
||||||
ClangTokenGroup tokens = decompilation.getCCodeMarkup();
|
ClangTokenGroup tokens = decompilation.getCCodeMarkup();
|
||||||
|
|
||||||
// TODO delete this when the ticket settles down
|
// TODO delete this when the ticket settles down
|
||||||
// dumpTokens(tokens, 0);
|
// dumpTokens(tokens, 0);
|
||||||
// dumpTokenNames(tokens, 0);
|
// dumpTokenNames(tokens, 0);
|
||||||
|
|
||||||
|
@ -339,15 +316,15 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uses the given line to find variables (also parameters and return types) and any
|
* Uses the given line to find variables (also parameters and return types) and any
|
||||||
* accesses to them in that line. A given variable may be used directly or, as in
|
* accesses to them in that line. A given variable may be used directly or, as in
|
||||||
* the case with Composite types, may have one of its fields accessed. Each result
|
* the case with Composite types, may have one of its fields accessed. Each result
|
||||||
* found by this method will be at least a variable access and may also itself have
|
* found by this method will be at least a variable access and may also itself have
|
||||||
* field accesses.
|
* field accesses.
|
||||||
*
|
*
|
||||||
* <p>Sometimes a line is structured such that there are anonymous variable accesses. This
|
* <p>Sometimes a line is structured such that there are anonymous variable accesses. This
|
||||||
* is the case where a Composite is being accessed, but the Composite itself is
|
* is the case where a Composite is being accessed, but the Composite itself is
|
||||||
* not a variable in the current function. See {@link AnonymousVariableAccessDR} for
|
* not a variable in the current function. See {@link AnonymousVariableAccessDR} for
|
||||||
* more details.
|
* more details.
|
||||||
*
|
*
|
||||||
* @param line the current line being processed from the Decompiler
|
* @param line the current line being processed from the Decompiler
|
||||||
|
@ -396,14 +373,14 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
||||||
else if (token instanceof ClangVariableToken) {
|
else if (token instanceof ClangVariableToken) {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Observations:
|
// Observations:
|
||||||
// 1) 'access' will be null if we are on a C statement that
|
// 1) 'access' will be null if we are on a C statement that
|
||||||
// is a declaration (parameter or variable). In this case,
|
// is a declaration (parameter or variable). In this case,
|
||||||
// 'declaration' will be an instance of VariableDR.
|
// 'declaration' will be an instance of VariableDR.
|
||||||
// 2) 'access' will be null the first time a variable is used in
|
// 2) 'access' will be null the first time a variable is used in
|
||||||
// a statement.
|
// a statement.
|
||||||
// 3) if 'access' is non-null, but already has a variable assigned,
|
// 3) if 'access' is non-null, but already has a variable assigned,
|
||||||
// then this means the current ClangVariableToken represents a new
|
// then this means the current ClangVariableToken represents a new
|
||||||
// variable access/usage.
|
// variable access/usage.
|
||||||
//
|
//
|
||||||
if (declaration != null) {
|
if (declaration != null) {
|
||||||
|
@ -427,7 +404,7 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
||||||
|
|
||||||
if (access == null) {
|
if (access == null) {
|
||||||
// Uh-oh. I've only seen this when line-wrapping is happening. In that
|
// Uh-oh. I've only seen this when line-wrapping is happening. In that
|
||||||
// case, try to get the last variable that we've seen and assume that
|
// case, try to get the last variable that we've seen and assume that
|
||||||
// is the variable to which this field belongs.
|
// is the variable to which this field belongs.
|
||||||
access = getLastAccess(results);
|
access = getLastAccess(results);
|
||||||
if (access == null) {
|
if (access == null) {
|
||||||
|
@ -442,7 +419,7 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
||||||
|
|
||||||
ClangFieldToken field = (ClangFieldToken) token;
|
ClangFieldToken field = (ClangFieldToken) token;
|
||||||
if (typesDoNotMatch(access, field)) {
|
if (typesDoNotMatch(access, field)) {
|
||||||
// this can happen when a field is used anonymously, such as directly
|
// this can happen when a field is used anonymously, such as directly
|
||||||
// after a nested array index operation
|
// after a nested array index operation
|
||||||
results.add(new AnonymousVariableAccessDR(line, field));
|
results.add(new AnonymousVariableAccessDR(line, field));
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -174,7 +174,7 @@ public abstract class DecompilerReference {
|
||||||
return "{\n" +
|
return "{\n" +
|
||||||
"\tvariable: " + StringUtilities.toStringWithIndent(variable) + ",\n" +
|
"\tvariable: " + StringUtilities.toStringWithIndent(variable) + ",\n" +
|
||||||
"\tdata type: " + getDataType() + ",\n"+
|
"\tdata type: " + getDataType() + ",\n"+
|
||||||
"\tline " + getContext() + ",\n" +
|
"\tline " + StringUtilities.toStringWithIndent(getContext().getPlainText()) + ",\n" +
|
||||||
"\tfunction: " + getFunction() + "\n" +
|
"\tfunction: " + getFunction() + "\n" +
|
||||||
"}";
|
"}";
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
|
|
|
@ -120,6 +120,16 @@ public class VariableAccessDR extends DecompilerReference {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (potentialField == null) {
|
if (potentialField == null) {
|
||||||
|
|
||||||
|
// check for the case where we have not been passed a 'potential field', but the given
|
||||||
|
// 'var' is itself the field we seek, such as in an if statement like this:
|
||||||
|
// if (color == RED)
|
||||||
|
// where 'RED' is the variable we are checking
|
||||||
|
String name = var.getName();
|
||||||
|
if (fieldName.equals(name)) {
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
return null; // we seek a field, but there is none
|
return null; // we seek a field, but there is none
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,7 +278,7 @@ public class VariableAccessDR extends DecompilerReference {
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
return "{\n" +
|
return "{\n" +
|
||||||
"\tline " + getContext() + ",\n" +
|
"\tline " + getContext().getPlainText() + ",\n" +
|
||||||
"\tfunction: " + getFunction() + "\n" +
|
"\tfunction: " + getFunction() + "\n" +
|
||||||
"\tvariable: " + StringUtilities.toStringWithIndent(variable) + ",\n" +
|
"\tvariable: " + StringUtilities.toStringWithIndent(variable) + ",\n" +
|
||||||
"\tdata type: " + getDataType() + ",\n"+
|
"\tdata type: " + getDataType() + ",\n"+
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue