mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
GP-1556 - Added support for searching for structure fields by offset
This commit is contained in:
parent
883f5a687a
commit
812ea4fe1e
45 changed files with 1461 additions and 840 deletions
|
@ -20,30 +20,30 @@ import java.util.List;
|
|||
import ghidra.app.decompiler.ClangFieldToken;
|
||||
import ghidra.app.decompiler.ClangLine;
|
||||
import ghidra.app.services.DataTypeReference;
|
||||
import ghidra.app.services.FieldMatcher;
|
||||
import ghidra.program.model.data.Composite;
|
||||
import ghidra.program.model.data.DataType;
|
||||
|
||||
/**
|
||||
* This class represents the use of a field of a {@link Composite} data type <b>where there is
|
||||
* no variable in the Decompiler</b> for that data type. A normal variable access in the
|
||||
* Decompiler may look like so:
|
||||
* This class represents the use of a field of a {@link Composite} data type <b>where there is no
|
||||
* variable in the Decompiler</b> for that data type. A normal variable access in the Decompiler
|
||||
* may look like so:
|
||||
* <pre>
|
||||
* Foo f;
|
||||
* ...
|
||||
* return f.some_field;
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* Alternatively, an anonymous variable access would look like this:
|
||||
* <pre>
|
||||
* Bar b;
|
||||
* ...
|
||||
* return b-><b>foo_array[1].some_field</b>;
|
||||
* </pre>
|
||||
*
|
||||
* In this case, <code><b>foo_array[1]</b></code> is a <code>Foo</code>, whose
|
||||
* <code><b>some_field</b></code> is
|
||||
* being accessed anonymously, since there is no variable of <code>Foo</code> declared
|
||||
* in the current function.
|
||||
*
|
||||
* In this case, <code><b>foo_array[1]</b></code> is a <code>Foo</code>, whose
|
||||
* <code><b>some_field</b></code> is being accessed anonymously, since there is no variable of
|
||||
* <code>Foo</code> declared in the current function.
|
||||
*/
|
||||
public class AnonymousVariableAccessDR extends VariableAccessDR {
|
||||
|
||||
|
@ -52,42 +52,57 @@ public class AnonymousVariableAccessDR extends VariableAccessDR {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void accumulateMatches(DataType dt, String fieldName, List<DataTypeReference> results) {
|
||||
public void accumulateMatches(DataType dt, FieldMatcher fieldMatcher,
|
||||
List<DataTypeReference> results) {
|
||||
|
||||
//
|
||||
// This class is backed by a ClangFieldToken. That class's data type is the composite
|
||||
// that contains the field being accessed. A variable being accessed has 2 types being
|
||||
// This class is backed by a ClangFieldToken. That class's data type is the composite that
|
||||
// contains the field being accessed. A variable being accessed has 2 types being
|
||||
// touched: the aforementioned composite and the type of the field itself.
|
||||
//
|
||||
// This can match in one of two cases:
|
||||
// 1) the client seeks to match a given field inside of the containing composite, or
|
||||
// 2) the client seeks to match only the type, which means that the field type itself must match
|
||||
// 1) the passed in type must match the field type and not the parent type, or
|
||||
// 2) the passed in type must match the parent type, along with supplied field name/offset.
|
||||
//
|
||||
|
||||
ClangFieldToken field = (ClangFieldToken) sourceToken;
|
||||
DataType compositeType = field.getDataType();
|
||||
DataType fieldDt = DecompilerReference.getFieldDataType(field);
|
||||
|
||||
boolean matchesComposite = isEqual(dt, compositeType);
|
||||
boolean matchesField = isEqual(dt, fieldDt);
|
||||
boolean noMatch = !(matchesComposite || matchesField);
|
||||
boolean matchesCompositeType = isEqual(dt, compositeType);
|
||||
boolean matchesFieldType = isEqual(dt, fieldDt);
|
||||
boolean noMatch = !(matchesCompositeType || matchesFieldType);
|
||||
if (noMatch) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fieldName == null) {
|
||||
// case 2; no field name to check
|
||||
if (matchesField) {
|
||||
//
|
||||
// Case 1
|
||||
//
|
||||
// If the client did not specify a field to match, then we only want to match on the type
|
||||
// of this reference's field type and NOT the composite type, since this reference is
|
||||
// referring to the field and not the composite.
|
||||
//
|
||||
if (fieldMatcher.isIgnored()) {
|
||||
if (matchesFieldType) {
|
||||
// no field name and the search type matches this reference's field type
|
||||
results.add(createReference(variable));
|
||||
}
|
||||
// else there is no field and the search type does not match the reference's type
|
||||
return;
|
||||
}
|
||||
|
||||
// case 1; check the field name and the composite type
|
||||
if (matchesComposite && field.getText().equals(fieldName)) {
|
||||
results.add(
|
||||
new DataTypeReference(compositeType, fieldName, getFunction(), getAddress(),
|
||||
getContext()));
|
||||
//
|
||||
// Case 2
|
||||
//
|
||||
// The client has requested a particular field of the parent composite. We only have a
|
||||
// match if the parent type matches and the field name/offset matches.
|
||||
//
|
||||
String text = field.getText();
|
||||
int offset = field.getOffset();
|
||||
if (matchesCompositeType && fieldMatcher.matches(text, offset)) {
|
||||
results.add(new DataTypeReference(compositeType, fieldMatcher.getFieldName(),
|
||||
getFunction(), getAddress(), getContext()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,8 +28,7 @@ import ghidra.app.decompiler.parallel.*;
|
|||
import ghidra.app.plugin.core.datamgr.util.DataTypeUtils;
|
||||
import ghidra.app.plugin.core.navigation.locationreferences.LocationReference;
|
||||
import ghidra.app.plugin.core.navigation.locationreferences.ReferenceUtils;
|
||||
import ghidra.app.services.DataTypeReference;
|
||||
import ghidra.app.services.DataTypeReferenceFinder;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.BuiltInDataType;
|
||||
import ghidra.program.model.data.DataType;
|
||||
|
@ -58,10 +57,28 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
|||
|
||||
@Override
|
||||
public void findReferences(Program program, DataType dataType, String fieldName,
|
||||
Consumer<DataTypeReference> callback, TaskMonitor monitor) throws CancelledException {
|
||||
Consumer<DataTypeReference> consumer, TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
FieldMatcher fieldMatcher = new FieldMatcher(dataType, fieldName);
|
||||
DecompilerDataTypeFinderQCallback qCallback =
|
||||
new DecompilerDataTypeFinderQCallback(program, dataType, fieldName, callback);
|
||||
new DecompilerDataTypeFinderQCallback(program, dataType, fieldMatcher, consumer);
|
||||
doFindReferences(program, dataType, qCallback, consumer, monitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void findReferences(Program program, FieldMatcher fieldMatcher,
|
||||
Consumer<DataTypeReference> consumer, TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
DataType dataType = fieldMatcher.getDataType();
|
||||
DecompilerDataTypeFinderQCallback qCallback =
|
||||
new DecompilerDataTypeFinderQCallback(program, dataType, fieldMatcher, consumer);
|
||||
|
||||
doFindReferences(program, dataType, qCallback, consumer, monitor);
|
||||
}
|
||||
|
||||
private void doFindReferences(Program program, DataType dataType,
|
||||
DecompilerDataTypeFinderQCallback qCallback, Consumer<DataTypeReference> consumer,
|
||||
TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
Set<Function> functions = filterFunctions(program, dataType, monitor);
|
||||
|
||||
|
@ -87,7 +104,7 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
|||
buildTypeLineage(dt, types);
|
||||
|
||||
Set<Function> results = new HashSet<>();
|
||||
accumulateFunctionCallsToDefinedData(program, types, results, monitor);
|
||||
accumulateFunctionCallsToDefinedData(program, dt, types, results, monitor);
|
||||
|
||||
Listing listing = program.getListing();
|
||||
FunctionIterator it = listing.getFunctions(true);
|
||||
|
@ -115,21 +132,23 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
|||
return results;
|
||||
}
|
||||
|
||||
private void accumulateFunctionCallsToDefinedData(Program program, Set<DataType> potentialTypes,
|
||||
Set<Function> results, TaskMonitor monitor) throws CancelledException {
|
||||
private void accumulateFunctionCallsToDefinedData(Program program, DataType dataType,
|
||||
Set<DataType> potentialTypes, Set<Function> results, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
|
||||
Listing listing = program.getListing();
|
||||
AtomicInteger counter = new AtomicInteger();
|
||||
SetAccumulator<LocationReference> accumulator = new SetAccumulator<>();
|
||||
Predicate<Data> dataMatcher = data -> {
|
||||
counter.incrementAndGet();
|
||||
DataType dataType = data.getDataType();
|
||||
boolean matches = potentialTypes.contains(dataType);
|
||||
DataType dt = data.getDataType();
|
||||
boolean matches = potentialTypes.contains(dt);
|
||||
return matches;
|
||||
};
|
||||
|
||||
ReferenceUtils.findDataTypeMatchesInDefinedData(accumulator, program, dataMatcher, null,
|
||||
monitor);
|
||||
FieldMatcher emptyMatcher = new FieldMatcher(dataType);
|
||||
ReferenceUtils.findDataTypeMatchesInDefinedData(accumulator, program, dataMatcher,
|
||||
emptyMatcher, monitor);
|
||||
|
||||
for (LocationReference ref : accumulator) {
|
||||
Address address = ref.getLocationOfUse();
|
||||
|
@ -158,12 +177,10 @@ 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
|
||||
// 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.)
|
||||
// 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.)
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -207,16 +224,16 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
|||
|
||||
private Consumer<DataTypeReference> callback;
|
||||
private DataType dataType;
|
||||
private String fieldName;
|
||||
private FieldMatcher fieldMatcher;
|
||||
|
||||
/* Search for composite field access */
|
||||
DecompilerDataTypeFinderQCallback(Program program, DataType dataType, String fieldName,
|
||||
Consumer<DataTypeReference> callback) {
|
||||
DecompilerDataTypeFinderQCallback(Program program, DataType dataType,
|
||||
FieldMatcher fieldMatcher, Consumer<DataTypeReference> callback) {
|
||||
|
||||
super(program, new DecompilerConfigurer());
|
||||
|
||||
this.dataType = dataType;
|
||||
this.fieldName = fieldName;
|
||||
this.fieldMatcher = fieldMatcher;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
|
@ -230,7 +247,7 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
|||
}
|
||||
|
||||
DecompilerDataTypeFinder finder =
|
||||
new DecompilerDataTypeFinder(results, function, dataType, fieldName);
|
||||
new DecompilerDataTypeFinder(results, function, dataType, fieldMatcher);
|
||||
List<DataTypeReference> refs = finder.findUsage();
|
||||
|
||||
refs.forEach(r -> callback.accept(r));
|
||||
|
@ -263,14 +280,14 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
|||
private DecompileResults decompilation;
|
||||
private Function function;
|
||||
private DataType dataType;
|
||||
private String fieldName;
|
||||
private FieldMatcher fieldMatcher;
|
||||
|
||||
DecompilerDataTypeFinder(DecompileResults results, Function function, DataType dataType,
|
||||
String fieldName) {
|
||||
FieldMatcher fieldMatcher) {
|
||||
this.decompilation = results;
|
||||
this.function = function;
|
||||
this.dataType = dataType;
|
||||
this.fieldName = fieldName;
|
||||
this.fieldMatcher = fieldMatcher;
|
||||
}
|
||||
|
||||
List<DataTypeReference> findUsage() {
|
||||
|
@ -300,7 +317,7 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
|||
|
||||
/** Finds any search input match in the given reference */
|
||||
private void matchUsage(DecompilerReference reference, List<DataTypeReference> results) {
|
||||
reference.accumulateMatches(dataType, fieldName, results);
|
||||
reference.accumulateMatches(dataType, fieldMatcher, results);
|
||||
}
|
||||
|
||||
private List<DecompilerReference> findVariableReferences(ClangTokenGroup tokens) {
|
||||
|
@ -320,20 +337,20 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
|||
* 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
|
||||
* more details.
|
||||
*
|
||||
*
|
||||
* @param line the current line being processed from the Decompiler
|
||||
* @param results the accumulator into which matches will be placed
|
||||
*/
|
||||
private void findVariablesInLine(ClangLine line, List<DecompilerReference> results) {
|
||||
|
||||
List<ClangToken> allTokens = line.getAllTokens();
|
||||
Iterable<ClangToken> filteredTokens = IterableUtils.filteredIterable(allTokens,
|
||||
token -> {
|
||||
Iterable<ClangToken> filteredTokens =
|
||||
IterableUtils.filteredIterable(allTokens, token -> {
|
||||
// Only include desirable tokens (this is really just for easier debugging).
|
||||
// Update this filter if the loop below ever needs other types of tokens.
|
||||
return (token instanceof ClangTypeToken) ||
|
||||
|
|
|
@ -23,7 +23,7 @@ import ghidra.program.model.data.*;
|
|||
import ghidra.util.Msg;
|
||||
|
||||
/**
|
||||
* A class that represents access to a Decompiler {@link ClangFieldToken} object. This is the field
|
||||
* A class that represents access to a Decompiler {@link ClangFieldToken} object. This is the field
|
||||
* of a variable, denoted by {@link ClangVariableToken}.
|
||||
*/
|
||||
public class DecompilerFieldAccess extends DecompilerVariable {
|
||||
|
@ -73,6 +73,12 @@ public class DecompilerFieldAccess extends DecompilerVariable {
|
|||
return dt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOffset() {
|
||||
ClangFieldToken field = (ClangFieldToken) variable;
|
||||
return field.getOffset();
|
||||
}
|
||||
|
||||
protected DataType getBaseType(DataType dt) {
|
||||
if (dt instanceof Array) {
|
||||
return getBaseType(((Array) dt).getDataType());
|
||||
|
|
|
@ -21,6 +21,7 @@ import ghidra.app.decompiler.*;
|
|||
import ghidra.app.plugin.core.navigation.locationreferences.LocationReferenceContext;
|
||||
import ghidra.app.plugin.core.navigation.locationreferences.LocationReferenceContextBuilder;
|
||||
import ghidra.app.services.DataTypeReference;
|
||||
import ghidra.app.services.FieldMatcher;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
@ -51,12 +52,12 @@ public abstract class DecompilerReference {
|
|||
* The <tt>fieldName</tt> is optional. If not included, then only data type matches will
|
||||
* be sought. If it is included, then a match is only included when it is a reference
|
||||
* to the given data type where that type is being accessed by the given field name.
|
||||
*
|
||||
*
|
||||
* @param dt the data type to find
|
||||
* @param fieldName the optional field name used to restrict matches.
|
||||
* @param fieldMatcher the optional field matcher used to restrict matches.
|
||||
* @param results the accumulator object into which will be placed any matches
|
||||
*/
|
||||
public abstract void accumulateMatches(DataType dt, String fieldName,
|
||||
public abstract void accumulateMatches(DataType dt, FieldMatcher fieldMatcher,
|
||||
List<DataTypeReference> results);
|
||||
|
||||
public DecompilerVariable getVariable() {
|
||||
|
@ -160,7 +161,7 @@ public abstract class DecompilerReference {
|
|||
int offset = field.getOffset();
|
||||
int n = parent.getLength();
|
||||
if (offset >= 0 && offset < n) {
|
||||
DataTypeComponent dtc = parent.getComponentAt(field.getOffset());
|
||||
DataTypeComponent dtc = parent.getComponentContaining(field.getOffset());
|
||||
fieldDt = dtc.getDataType();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -188,6 +188,10 @@ public abstract class DecompilerVariable {
|
|||
return text;
|
||||
}
|
||||
|
||||
public int getOffset() {
|
||||
return Integer.MIN_VALUE; // subclasses can override
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String castString = casts.isEmpty() ? "" : "\tcasts: " + casts + ",\n";
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.util.List;
|
|||
import ghidra.app.decompiler.ClangLine;
|
||||
import ghidra.app.decompiler.ClangTypeToken;
|
||||
import ghidra.app.services.DataTypeReference;
|
||||
import ghidra.app.services.FieldMatcher;
|
||||
import ghidra.program.model.data.DataType;
|
||||
|
||||
public class ReturnTypeDR extends DecompilerReference {
|
||||
|
@ -29,11 +30,11 @@ public class ReturnTypeDR extends DecompilerReference {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void accumulateMatches(DataType dt, String fieldName, List<DataTypeReference> results) {
|
||||
public void accumulateMatches(DataType dt, FieldMatcher fieldMatcher,
|
||||
List<DataTypeReference> results) {
|
||||
|
||||
if (fieldName != null) {
|
||||
// Return Types do not have any field usage
|
||||
return;
|
||||
if (!fieldMatcher.isIgnored()) {
|
||||
return; // Return Types do not have any field usage
|
||||
}
|
||||
|
||||
DataType myDt = getDataType();
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.util.List;
|
|||
import ghidra.app.decompiler.*;
|
||||
import ghidra.app.plugin.core.navigation.locationreferences.LocationReferenceContext;
|
||||
import ghidra.app.services.DataTypeReference;
|
||||
import ghidra.app.services.FieldMatcher;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
@ -58,10 +59,11 @@ public class VariableAccessDR extends DecompilerReference {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void accumulateMatches(DataType dt, String fieldName, List<DataTypeReference> results) {
|
||||
public void accumulateMatches(DataType dt, FieldMatcher fieldMatcher,
|
||||
List<DataTypeReference> results) {
|
||||
|
||||
if (fields.isEmpty()) {
|
||||
DecompilerVariable var = getMatch(dt, fieldName, variable, null);
|
||||
DecompilerVariable var = getMatch(dt, fieldMatcher, variable, null);
|
||||
if (var != null) {
|
||||
DataTypeReference ref = createReference(var);
|
||||
results.add(ref);
|
||||
|
@ -77,7 +79,7 @@ public class VariableAccessDR extends DecompilerReference {
|
|||
for (DecompilerVariable field : fields) {
|
||||
|
||||
DecompilerVariable next = field;
|
||||
DecompilerVariable var = getMatch(dt, fieldName, start, next);
|
||||
DecompilerVariable var = getMatch(dt, fieldMatcher, start, next);
|
||||
if (var != null) {
|
||||
DataTypeReference ref = createReference(var, next);
|
||||
results.add(ref);
|
||||
|
@ -87,46 +89,46 @@ public class VariableAccessDR extends DecompilerReference {
|
|||
}
|
||||
|
||||
//
|
||||
// Handle the last variable by itself (for the case where we are matching just on the
|
||||
// type, with no field name)
|
||||
// Handle the last variable by itself (for the case where we are matching just on the type,
|
||||
// with no field name)
|
||||
//
|
||||
if (fieldName != null) {
|
||||
if (fieldMatcher.isIgnored()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DecompilerVariable var = getMatch(dt, null, start, null);
|
||||
DecompilerVariable var = getMatch(dt, fieldMatcher, start, null);
|
||||
if (var != null) {
|
||||
DataTypeReference ref = createReference(var);
|
||||
results.add(ref);
|
||||
}
|
||||
}
|
||||
|
||||
private DecompilerVariable getMatch(DataType dt, String fieldName, DecompilerVariable var,
|
||||
DecompilerVariable potentialField) {
|
||||
private DecompilerVariable getMatch(DataType dt, FieldMatcher fieldMatcher,
|
||||
DecompilerVariable var, DecompilerVariable potentialField) {
|
||||
|
||||
// Note: for now, I ignore the precedence of casting; if any cast type is a match, then
|
||||
// signal hooray
|
||||
boolean searchForField = fieldName != null;
|
||||
boolean searchForField = !fieldMatcher.isIgnored();
|
||||
DecompilerVariable fieldVar = searchForField ? potentialField : null;
|
||||
DecompilerVariable match = getMatchingVarialbe(dt, var, fieldVar);
|
||||
if (match == null) {
|
||||
// wrong type, nothing to do
|
||||
return null;
|
||||
return null; // wrong type, nothing to do
|
||||
}
|
||||
|
||||
// Matches on the type, does the field match?
|
||||
if (fieldName == null) {
|
||||
if (fieldMatcher.isIgnored()) {
|
||||
return match; // no field to match
|
||||
}
|
||||
|
||||
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:
|
||||
// 'var' is itself may be 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)) {
|
||||
int offset = var.getOffset();
|
||||
if (fieldMatcher.matches(name, offset)) {
|
||||
return var;
|
||||
}
|
||||
|
||||
|
@ -134,7 +136,8 @@ public class VariableAccessDR extends DecompilerReference {
|
|||
}
|
||||
|
||||
String name = potentialField.getName();
|
||||
if (fieldName.equals(name)) {
|
||||
int offset = potentialField.getOffset();
|
||||
if (fieldMatcher.matches(name, offset)) {
|
||||
return match;
|
||||
}
|
||||
return null;
|
||||
|
@ -156,13 +159,13 @@ public class VariableAccessDR extends DecompilerReference {
|
|||
|
||||
//
|
||||
// Unusual Code Alert!
|
||||
// It is a bit odd to check the field when you are looking for the type that contains
|
||||
// the field. BUT, in the Decompiler, SOMETIMES the 'field' happens to have the
|
||||
// data type of the thing that contains it. So, if you have:
|
||||
// It is a bit odd to check the field when you are looking for the type that contains the
|
||||
// field. BUT, in the Decompiler, SOMETIMES the 'field' happens to have the data type of
|
||||
// the thing that contains it. So, if you have:
|
||||
// foo.bar
|
||||
// then the 'bar' field will have a data type of Foo. Unfortunately, this is not
|
||||
// always the case. For now, when the variable is global, we need to check the field
|
||||
// Sad face emoji.
|
||||
// then the 'bar' field will have a data type of Foo. Unfortunately, this is not always
|
||||
// the case. For now, when the variable is global, we need to check the field. Sad face
|
||||
// emoji.
|
||||
//
|
||||
HighVariable highVariable = var.variable.getHighVariable();
|
||||
if (highVariable instanceof HighGlobal) {
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.util.List;
|
|||
import ghidra.app.decompiler.*;
|
||||
import ghidra.app.plugin.core.navigation.locationreferences.LocationReferenceContext;
|
||||
import ghidra.app.services.DataTypeReference;
|
||||
import ghidra.app.services.FieldMatcher;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
@ -52,7 +53,8 @@ public abstract class VariableDR extends DecompilerReference {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void accumulateMatches(DataType dt, String fieldName, List<DataTypeReference> results) {
|
||||
public void accumulateMatches(DataType dt, FieldMatcher fieldMatcher,
|
||||
List<DataTypeReference> results) {
|
||||
|
||||
if (variable == null) {
|
||||
// This implies our API was misused in that a variable was never set after creation
|
||||
|
@ -61,21 +63,18 @@ public abstract class VariableDR extends DecompilerReference {
|
|||
|
||||
DataType dataType = getDataType();
|
||||
if (!isEqual(dataType, dt)) {
|
||||
// wrong type, nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
LocationReferenceContext context = getContext();
|
||||
Function function = getFunction();
|
||||
Address address = getAddress();
|
||||
if (fieldName == null) {
|
||||
// no field to check, a match on the the type is good enough
|
||||
results.add(new DataTypeReference(dataType, null, getFunction(), address, context));
|
||||
return;
|
||||
return; // wrong type, nothing to do
|
||||
}
|
||||
|
||||
String name = variable.getName();
|
||||
if (name.equals(fieldName)) {
|
||||
int offset = variable.getOffset();
|
||||
if (fieldMatcher.matches(name, offset)) {
|
||||
|
||||
// this will be null if the field matcher is empty
|
||||
String fieldName = fieldMatcher.getFieldName();
|
||||
Function function = getFunction();
|
||||
Address address = getAddress();
|
||||
LocationReferenceContext context = getContext();
|
||||
results.add(new DataTypeReference(dataType, fieldName, function, address, context));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue