GP-1514 - Find References to - Added support for finding usage of enum

fields

Closes #1967
This commit is contained in:
dragonmacher 2021-11-26 14:36:20 -05:00
parent 2fb860bcd7
commit 33b2bbbd0b
15 changed files with 108 additions and 135 deletions

View file

@ -31,7 +31,8 @@ import ghidra.app.plugin.core.navigation.locationreferences.ReferenceUtils;
import ghidra.app.services.DataTypeReference;
import ghidra.app.services.DataTypeReferenceFinder;
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.util.Msg;
import ghidra.util.StringUtilities;
@ -40,7 +41,7 @@ import ghidra.util.exception.CancelledException;
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.
*/
public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinder {
@ -52,29 +53,11 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
@Override
public void findReferences(Program program, DataType dataType,
Consumer<DataTypeReference> callback, TaskMonitor monitor) throws CancelledException {
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();
}
findReferences(program, dataType, null, callback, monitor);
}
@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 {
DecompilerDataTypeFinderQCallback qCallback =
@ -175,12 +158,12 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
// We have a different type, should we search for it?
if (baseType instanceof BuiltInDataType) {
// When given a wrapper type (e.g., typedef) , ignore
// built-ins (e.g., int, byte, etc), as
// When given a wrapper type (e.g., typedef) , ignore
// built-ins (e.g., int, byte, etc), as
// 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
// this check, which allows the user to search directly for a
// built-in type, if they wish.)
// 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
// built-in type, if they wish.)
return;
}
@ -227,12 +210,6 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
private DataType dataType;
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 */
DecompilerDataTypeFinderQCallback(Program program, DataType dataType, String fieldName,
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.
*/
private static class DecompilerDataTypeFinder {
@ -308,7 +285,7 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
ClangTokenGroup tokens = decompilation.getCCodeMarkup();
// TODO delete this when the ticket settles down
// TODO delete this when the ticket settles down
// dumpTokens(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
* accesses to them in that line. A given variable may be used directly or, as in
* 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
* 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
* field accesses.
*
* <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
* not a variable in the current function. See {@link AnonymousVariableAccessDR} for
* not a variable in the current function. See {@link AnonymousVariableAccessDR} for
* more details.
*
* @param line the current line being processed from the Decompiler
@ -396,14 +373,14 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
else if (token instanceof ClangVariableToken) {
//
// Observations:
// 1) 'access' will be null if we are on a C statement that
// is a declaration (parameter or variable). In this case,
// Observations:
// 1) 'access' will be null if we are on a C statement that
// is a declaration (parameter or variable). In this case,
// 'declaration' will be an instance of VariableDR.
// 2) 'access' will be null the first time a variable is used in
// a statement.
// 3) if 'access' is non-null, but already has a variable assigned,
// then this means the current ClangVariableToken represents a new
// 3) if 'access' is non-null, but already has a variable assigned,
// then this means the current ClangVariableToken represents a new
// variable access/usage.
//
if (declaration != null) {
@ -427,7 +404,7 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
if (access == null) {
// 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.
access = getLastAccess(results);
if (access == null) {
@ -442,7 +419,7 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
ClangFieldToken field = (ClangFieldToken) token;
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
results.add(new AnonymousVariableAccessDR(line, field));
continue;

View file

@ -174,7 +174,7 @@ public abstract class DecompilerReference {
return "{\n" +
"\tvariable: " + StringUtilities.toStringWithIndent(variable) + ",\n" +
"\tdata type: " + getDataType() + ",\n"+
"\tline " + getContext() + ",\n" +
"\tline " + StringUtilities.toStringWithIndent(getContext().getPlainText()) + ",\n" +
"\tfunction: " + getFunction() + "\n" +
"}";
//@formatter:on

View file

@ -120,6 +120,16 @@ public class VariableAccessDR extends DecompilerReference {
}
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
}
@ -268,7 +278,7 @@ public class VariableAccessDR extends DecompilerReference {
//@formatter:off
return "{\n" +
"\tline " + getContext() + ",\n" +
"\tline " + getContext().getPlainText() + ",\n" +
"\tfunction: " + getFunction() + "\n" +
"\tvariable: " + StringUtilities.toStringWithIndent(variable) + ",\n" +
"\tdata type: " + getDataType() + ",\n"+