Merge remote-tracking branch 'origin/GT-3647-dragonmacher-find-datatypes-fix'

This commit is contained in:
ghidravore
2020-08-04 16:54:28 -04:00
6 changed files with 89 additions and 20 deletions

View File

@@ -27,6 +27,7 @@ import ghidra.util.Msg;
import ghidra.util.xml.SpecXmlUtils;
import ghidra.xml.XmlElement;
import ghidra.xml.XmlPullParser;
/**
*
*
@@ -45,21 +46,21 @@ public class ClangVariableDecl extends ClangTokenGroup {
}
public DataType getDataType() {
return datatype;
return datatype;
}
public HighVariable getHighVariable() {
return typevar;
}
@Override
public void restoreFromXML(XmlPullParser parser,PcodeFactory pfactory) {
XmlElement node = parser.peek();
super.restoreFromXML(parser,pfactory);
public void restoreFromXML(XmlPullParser parser, PcodeFactory pfactory) {
XmlElement node = parser.peek();
super.restoreFromXML(parser, pfactory);
long symref = SpecXmlUtils.decodeLong(node.getAttribute(ClangXML.SYMREF));
HighSymbol sym = pfactory.getSymbol(symref);
if (sym == null) {
Msg.error(this, "Invalid symbol reference: " + symref);
Msg.error(this, "Invalid symbol reference: " + symref + " in " + Parent());
return;
}
typevar = sym.getHighVariable();

View File

@@ -45,7 +45,7 @@ import ghidra.program.model.data.DataType;
* being accessed anonymously, since there is no variable of <code>Foo</code> declared
* in the current function.
*/
public class AnonymousVariableAccessDR extends DecompilerReference {
public class AnonymousVariableAccessDR extends VariableAccessDR {
protected AnonymousVariableAccessDR(ClangLine line, ClangFieldToken token) {
super(line, token);
@@ -54,16 +54,40 @@ public class AnonymousVariableAccessDR extends DecompilerReference {
@Override
public void accumulateMatches(DataType dt, String fieldName, 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
// 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
//
ClangFieldToken field = (ClangFieldToken) sourceToken;
DataType fieldDt = field.getDataType();
if (!isEqual(dt, fieldDt)) {
DataType compositeType = field.getDataType();
DataType fieldDt = DecompilerReference.getFieldDataType(field);
boolean matchesComposite = isEqual(dt, compositeType);
boolean matchesField = isEqual(dt, fieldDt);
boolean noMatch = !(matchesComposite || matchesField);
if (noMatch) {
return;
}
if (field.getText().equals(fieldName)) {
results.add(new DataTypeReference(fieldDt, fieldName, getFunction(), getAddress(),
getContext()));
if (fieldName == null) {
// case 2; no field name to check
if (matchesField) {
results.add(createReference(variable));
}
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()));
}
}
}

View File

@@ -461,8 +461,14 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
return false; // should not happen
}
// Note: the field's type is that of the parent structure, not the field. We want the
// field's type, so we must retrieve that.
DataType fieldDt = DecompilerReference.getFieldDataType(field);
// unusual code: getDataType() on the variable may return the type of the field being
// accessed. Contrastingly, getDataType() on the field may return the
// type of the parent structure.
DataType variableDt = variable.getDataType();
DataType fieldDt = field.getDataType();
return !DecompilerReference.isEqual(variableDt, fieldDt);
}

View File

@@ -18,8 +18,7 @@ package ghidra.app.extension.datatype.finder;
import java.util.Arrays;
import java.util.List;
import ghidra.app.decompiler.ClangLine;
import ghidra.app.decompiler.ClangToken;
import ghidra.app.decompiler.*;
import ghidra.app.plugin.core.navigation.locationreferences.ReferenceUtils;
import ghidra.app.services.DataTypeReference;
import ghidra.program.model.address.Address;
@@ -103,12 +102,26 @@ public abstract class DecompilerReference {
public static boolean isEquivalent(DataType dt1, DataType dt2) {
DataType base1 = getBaseType(dt1);
DataType base2 = getBaseType(dt2);
if (base1 == null || base2 == null) {
// this should not happen, but we have seen sometimes that ClangVariableDecl
// cannot find its HighSymbol from which to get a datatype
return false;
}
return base1.isEquivalent(base2);
}
public static boolean isEqual(DataType dt1, DataType dt2) {
DataType base1 = getBaseType(dt1);
DataType base2 = getBaseType(dt2);
if (base1 == null || base2 == null) {
// this should not happen, but we have seen sometimes that ClangVariableDecl
// cannot find its HighSymbol from which to get a datatype
return false;
}
return base1.equals(base2);
}
@@ -129,6 +142,21 @@ public abstract class DecompilerReference {
return dt;
}
public static DataType getFieldDataType(ClangFieldToken field) {
DataType fieldDt = field.getDataType();
fieldDt = DecompilerReference.getBaseType(fieldDt);
if (fieldDt instanceof Structure) {
Structure parent = (Structure) fieldDt;
int offset = field.getOffset();
int n = parent.getLength();
if (offset >= 0 && offset < n) {
DataTypeComponent dtc = parent.getComponentAt(field.getOffset());
fieldDt = dtc.getDataType();
}
}
return fieldDt;
}
@Override
public String toString() {

View File

@@ -51,6 +51,12 @@ public abstract class DecompilerVariable {
return ((ClangTypeToken) variable).getDataType();
}
// not sure if we need this; the type returned here is the structure and not the
// field's type
// if (variable instanceof ClangFieldToken) {
// return ((ClangFieldToken) variable).getDataType();
// }
// Note: this is the icky part of the API. How to know from where to get the data type?
HighVariable highVariable = variable.getHighVariable();
if (highVariable != null) {

View File

@@ -39,6 +39,10 @@ public class VariableAccessDR extends DecompilerReference {
super(line, null /* This class does not always have a 'type' token */);
}
protected VariableAccessDR(ClangLine line, ClangFieldToken token) {
super(line, token);
}
void setVariable(ClangVariableToken token, List<DecompilerVariable> casts) {
if (variable != null) {
throw new AssertException("Decompiler variable is already set for this access");
@@ -184,7 +188,7 @@ public class VariableAccessDR extends DecompilerReference {
return matches;
}
private DataTypeReference createReference(DecompilerVariable var) {
protected DataTypeReference createReference(DecompilerVariable var) {
DataType dataType = var.getDataType();
String context = getContext(var);
@@ -263,11 +267,11 @@ public class VariableAccessDR extends DecompilerReference {
//@formatter:off
return "{\n" +
"\tline " + getContext() + ",\n" +
"\tfunction: " + getFunction() + "\n" +
"\tvariable: " + StringUtilities.toStringWithIndent(variable) + ",\n" +
"\tdata type: " + getDataType() + ",\n"+
subFieldsString +
"\tline " + getContext() + ",\n" +
"\tfunction: " + getFunction() + "\n" +
"}";
//@formatter:on
}