GP-1297 More explicit support for typedefs in the decompiler (Closes #2393, Closes #3249)

This commit is contained in:
caheckman 2021-09-15 16:50:19 -04:00 committed by ghidra1
parent 8b2ea61e27
commit 8aed810d4a
10 changed files with 259 additions and 124 deletions

View file

@ -102,7 +102,7 @@ public abstract class ConstantPool {
SpecXmlUtils.xmlEscape(buf, token);
buf.append("</token>\n");
}
buf.append(dtmanage.buildTypeRef(type, type.getLength()));
dtmanage.buildTypeRef(buf, type, type.getLength());
buf.append("</cpoolrec>\n");
return buf;
}

View file

@ -378,7 +378,7 @@ public class FunctionPrototype {
res.append("<addr/>\n "); // Don't specify where return type is stored
}
res.append(dtmanage.buildTypeRef(returntype, sz));
dtmanage.buildTypeRef(res, returntype, sz);
res.append(" </returnsym>\n");
if (injectname != null) {
res.append("<inject>");
@ -404,7 +404,7 @@ public class FunctionPrototype {
if (sz < 0) {
sz = 1;
}
res.append(dtmanage.buildTypeRef(dt, sz));
dtmanage.buildTypeRef(res, dt, sz);
res.append("</param>\n");
}
res.append("</internallist>\n");

View file

@ -32,7 +32,7 @@ import ghidra.xml.XmlPullParser;
* SymbolEntry for each mapping.
*/
public class HighSymbol {
public static final long ID_BASE = 0x4000000000000000L; // Put keys in the dynamic symbol portion of the key space
protected String name;
protected DataType type;
@ -45,7 +45,7 @@ public class HighSymbol {
private boolean isHidden; // True if we are hidden symbol containing pointer to where return value is stored
private long id; // Unique id of this symbol
protected SymbolEntry[] entryList; // List of mappings for this symbol
private HighVariable highVariable;
private PcodeDataTypeManager dtmanage; // Datatype manager for XML generation
@ -169,7 +169,7 @@ public class HighSymbol {
public void setHighVariable(HighVariable high) {
this.highVariable = high;
}
/**
* Get the HighVariable associate with this symbol if any. This allows the user to go straight
* into the decompiler's function to see how the symbol gets manipulated.
@ -208,7 +208,7 @@ public class HighSymbol {
public int getSize() {
return entryList[0].getSize();
}
/**
* Get the first code Address, within the function, where this symbol's storage actually
* holds the value of the symbol. If there is more than one mapping for the symbol, this
@ -401,7 +401,7 @@ public class HighSymbol {
buf.append("<symbol");
saveXMLHeader(buf);
buf.append(">\n");
buf.append(dtmanage.buildTypeRef(type, getSize()));
dtmanage.buildTypeRef(buf, type, getSize());
buf.append("</symbol>\n");
}

View file

@ -164,7 +164,7 @@ public class PcodeDataTypeManager {
* element
*/
public DataType readXMLDataType(XmlPullParser parser) throws PcodeXMLException {
XmlElement el = parser.start("type", "void", "typeref");
XmlElement el = parser.start("type", "void", "typeref", "def");
try {
if (el == null) {
throw new PcodeXMLException("Bad <type> tag");
@ -176,6 +176,12 @@ public class PcodeDataTypeManager {
if (el.getName().equals("typeref")) {
return findBaseType(el.getAttribute("name"), el.getAttribute("id"));
}
if (el.getName().equals("def")) {
String nameStr = el.getAttribute("name");
String idStr = el.getAttribute("id");
parser.discardSubTree(); // Get rid of unused <typeref>
return findBaseType(nameStr, idStr);
}
String name = el.getAttribute("name");
if (name.length() != 0) {
return findBaseType(name, el.getAttribute("id"));
@ -249,25 +255,29 @@ public class PcodeDataTypeManager {
* fully describing the data-type. Where possible a {@code <typeref>} tag is produced, which just gives
* the name of the data-type, deferring a full description of the data-type. For certain simple or
* nameless data-types, a {@code <type>} tag is emitted giving a full description.
* @param resBuf is the stream to append the tag to
* @param type is the data-type to be converted
* @param size is the size in bytes of the specific instance of the data-type
* @return a StringBuilder containing the XML tag
*/
public StringBuilder buildTypeRef(DataType type, int size) {
public void buildTypeRef(StringBuilder resBuf, DataType type, int size) {
if (type != null && type.getDataTypeManager() != progDataTypes) {
type = type.clone(progDataTypes);
}
if ((type instanceof VoidDataType) || (type == null)) {
return buildType(type, size);
buildType(resBuf, type, size);
return;
}
if (type instanceof AbstractIntegerDataType) {
return buildType(type, size);
buildType(resBuf, type, size);
return;
}
if (type instanceof Pointer) {
return buildType(type, size);
buildType(resBuf, type, size);
return;
}
if (type instanceof Array) {
return buildType(type, size);
buildType(resBuf, type, size);
return;
}
if (type instanceof FunctionDefinition) {
long id = progDataTypes.getID(type);
@ -275,14 +285,15 @@ public class PcodeDataTypeManager {
// Its possible the FunctionDefinition was built on the fly and is not
// a permanent data-type of the program with an ID. In this case, we can't
// construct a <typeref> tag but must build a full <type> tag.
return buildType(type, size);
buildType(resBuf, type, size);
return;
}
size = 1;
}
else if (type.getLength() <= 0) {
return buildType(type, size);
buildType(resBuf, type, size);
return;
}
StringBuilder resBuf = new StringBuilder();
resBuf.append("<typeref");
if (type instanceof BuiltIn) {
SpecXmlUtils.xmlEscapeAttribute(resBuf, "name",
@ -300,24 +311,28 @@ public class PcodeDataTypeManager {
}
}
resBuf.append("/>");
return resBuf;
}
private StringBuilder getCharTypeRef(int size) {
private void appendCharTypeRef(StringBuilder resBuf, int size) {
if (size == dataOrganization.getCharSize()) {
return new StringBuilder("<typeref name=\"char\"/>"); // could have size 1 or 2
resBuf.append("<typeref name=\"char\"/>"); // could have size 1 or 2
return;
}
if (size == dataOrganization.getWideCharSize()) {
return new StringBuilder("<typeref name=\"wchar_t\"/>");
resBuf.append("<typeref name=\"wchar_t\"/>");
return;
}
if (size == 2) {
return new StringBuilder("<typeref name=\"wchar16\"/>");
resBuf.append("<typeref name=\"wchar16\"/>");
return;
}
if (size == 4) {
return new StringBuilder("<typeref name=\"wchar32\"/>");
resBuf.append("<typeref name=\"wchar32\"/>");
return;
}
if (size == 1) {
return new StringBuilder("<typeref name=\"byte\"/>");
resBuf.append("<typeref name=\"byte\"/>");
return;
}
throw new IllegalArgumentException("Unsupported character size");
}
@ -343,22 +358,10 @@ public class PcodeDataTypeManager {
resBuf.append("</field>\n");
}
private String buildTypeInternal(DataType origType, int size) { // Build all of type except name attribute
DataType type;
if (origType instanceof TypeDef) {
type = ((TypeDef) origType).getBaseDataType();
}
else {
type = origType;
}
StringBuilder resBuf = new StringBuilder();
private String buildTypeInternal(StringBuilder resBuf, DataType type, int size) {
resBuf.append("<type");
if (type instanceof Pointer) {
if (origType == type) {
SpecXmlUtils.encodeStringAttribute(resBuf, "name", "");
}
else {
appendNameIdAttributes(resBuf, origType);
}
SpecXmlUtils.encodeStringAttribute(resBuf, "name", "");
SpecXmlUtils.encodeStringAttribute(resBuf, "metatype", "ptr");
int ptrLen = type.getLength();
if (ptrLen <= 0) {
@ -375,54 +378,46 @@ public class PcodeDataTypeManager {
ptrto = ptrto.clone(progDataTypes);
}
StringBuilder ptrtoTypeRef;
if (ptrto == null) {
ptrtoTypeRef = buildTypeRef(DefaultDataType.dataType, 1);
buildTypeRef(resBuf, DefaultDataType.dataType, 1);
}
else if (ptrto instanceof AbstractStringDataType) {
if ((ptrto instanceof StringDataType) ||
(type instanceof TerminatedStringDataType)) { // Convert pointer to string
ptrtoTypeRef = getCharTypeRef(dataOrganization.getCharSize()); // to pointer to char
appendCharTypeRef(resBuf, dataOrganization.getCharSize()); // to pointer to char
}
else if (ptrto instanceof StringUTF8DataType) { // Convert pointer to string
// TODO: Need to ensure that UTF8 decoding applies
ptrtoTypeRef = getCharTypeRef(1); // to pointer to char
appendCharTypeRef(resBuf, 1); // to pointer to char
}
else if ((ptrto instanceof UnicodeDataType) ||
(ptrto instanceof TerminatedUnicodeDataType)) {
ptrtoTypeRef = getCharTypeRef(2);
appendCharTypeRef(resBuf, 2);
}
else if ((ptrto instanceof Unicode32DataType) ||
(ptrto instanceof TerminatedUnicode32DataType)) {
ptrtoTypeRef = getCharTypeRef(4);
appendCharTypeRef(resBuf, 4);
}
else {
ptrtoTypeRef = new StringBuilder();
ptrtoTypeRef.append("<type");
appendNameIdAttributes(ptrtoTypeRef, ptrto);
appendOpaqueString(ptrtoTypeRef, ptrto, 16384);
ptrtoTypeRef.append("</type>\n");
resBuf.append("<type");
appendNameIdAttributes(resBuf, ptrto);
appendOpaqueString(resBuf, ptrto, 16384);
resBuf.append("</type>\n");
}
}
else if (ptrto instanceof FunctionDefinition) {
// FunctionDefinition may have size of -1, do not translate to undefined
ptrtoTypeRef = buildTypeRef(ptrto, ptrto.getLength());
buildTypeRef(resBuf, ptrto, ptrto.getLength());
}
else if (ptrto.getLength() < 0 && !(ptrto instanceof FunctionDefinition)) {
ptrtoTypeRef = buildTypeRef(Undefined1DataType.dataType, 1);
buildTypeRef(resBuf, Undefined1DataType.dataType, 1);
}
else {
ptrtoTypeRef = buildTypeRef(ptrto, ptrto.getLength());
buildTypeRef(resBuf, ptrto, ptrto.getLength());
}
resBuf.append(ptrtoTypeRef);
}
else if (type instanceof Array) {
if (origType == type) {
SpecXmlUtils.encodeStringAttribute(resBuf, "name", "");
}
else {
appendNameIdAttributes(resBuf, origType);
}
SpecXmlUtils.encodeStringAttribute(resBuf, "name", "");
int sz = type.getLength();
if (sz == 0) {
sz = size;
@ -432,11 +427,10 @@ public class PcodeDataTypeManager {
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "arraysize",
((Array) type).getNumElements());
resBuf.append('>');
resBuf.append(
buildTypeRef(((Array) type).getDataType(), ((Array) type).getElementLength()));
buildTypeRef(resBuf, ((Array) type).getDataType(), ((Array) type).getElementLength());
}
else if (type instanceof Structure) {
appendNameIdAttributes(resBuf, origType);
appendNameIdAttributes(resBuf, type);
// if size is 0, insert an Undefined4 component
//
int sz = type.getLength();
@ -462,13 +456,13 @@ public class PcodeDataTypeManager {
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "offset", comp.getOffset());
resBuf.append('>');
DataType fieldtype = comp.getDataType();
resBuf.append(buildTypeRef(fieldtype, comp.getLength()));
buildTypeRef(resBuf, fieldtype, comp.getLength());
resBuf.append("</field>\n");
}
// TODO: trailing flexible array component not yet supported
}
else if (type instanceof Enum) {
appendNameIdAttributes(resBuf, origType);
appendNameIdAttributes(resBuf, type);
Enum enumDt = (Enum) type;
long[] keys = enumDt.getValues();
String metatype = "uint";
@ -490,7 +484,7 @@ public class PcodeDataTypeManager {
}
}
else if (type instanceof CharDataType) {
appendNameIdAttributes(resBuf, origType);
appendNameIdAttributes(resBuf, type);
boolean signed = ((CharDataType) type).isSigned();
int sz = type.getLength();
if (sz <= 0) {
@ -508,7 +502,7 @@ public class PcodeDataTypeManager {
}
else if (type instanceof WideCharDataType || type instanceof WideChar16DataType ||
type instanceof WideChar32DataType) {
appendNameIdAttributes(resBuf, origType);
appendNameIdAttributes(resBuf, type);
SpecXmlUtils.encodeStringAttribute(resBuf, "metatype", "int");
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "size", type.getLength());
SpecXmlUtils.encodeBooleanAttribute(resBuf, "utf", true);
@ -521,7 +515,7 @@ public class PcodeDataTypeManager {
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "size", size);
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "arraysize", size);
resBuf.append('>');
resBuf.append(getCharTypeRef(dataOrganization.getCharSize()));
appendCharTypeRef(resBuf, dataOrganization.getCharSize());
}
else if (type instanceof StringUTF8DataType) {
SpecXmlUtils.encodeStringAttribute(resBuf, "name", "");
@ -529,7 +523,7 @@ public class PcodeDataTypeManager {
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "size", size);
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "arraysize", size);
resBuf.append('>');
resBuf.append(getCharTypeRef(1)); // TODO: Need to ensure that UTF8 decoding applies
appendCharTypeRef(resBuf, 1); // TODO: Need to ensure that UTF8 decoding applies
}
else if ((type instanceof UnicodeDataType) ||
(type instanceof TerminatedUnicodeDataType)) {
@ -538,7 +532,7 @@ public class PcodeDataTypeManager {
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "size", size);
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "arraysize", size / 2);
resBuf.append('>');
resBuf.append(getCharTypeRef(2));
appendCharTypeRef(resBuf, 2);
}
else if ((type instanceof Unicode32DataType) ||
(type instanceof TerminatedUnicode32DataType)) {
@ -547,7 +541,7 @@ public class PcodeDataTypeManager {
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "size", size);
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "arraysize", size / 4);
resBuf.append('>');
resBuf.append(getCharTypeRef(4));
appendCharTypeRef(resBuf, 4);
}
else {
appendNameIdAttributes(resBuf, type);
@ -558,7 +552,7 @@ public class PcodeDataTypeManager {
if (size <= 0) {
size = 1;
}
appendNameIdAttributes(resBuf, origType);
appendNameIdAttributes(resBuf, type);
SpecXmlUtils.encodeStringAttribute(resBuf, "metatype", "code");
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "size", 1); // Force size of 1
resBuf.append('>');
@ -568,7 +562,7 @@ public class PcodeDataTypeManager {
fproto.buildPrototypeXML(resBuf, this);
}
else if (type instanceof BooleanDataType) {
appendNameIdAttributes(resBuf, origType);
appendNameIdAttributes(resBuf, type);
SpecXmlUtils.encodeStringAttribute(resBuf, "metatype", "bool");
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "size", type.getLength());
resBuf.append('>');
@ -579,13 +573,13 @@ public class PcodeDataTypeManager {
if (sz <= 0) {
sz = size;
}
appendNameIdAttributes(resBuf, origType);
appendNameIdAttributes(resBuf, type);
SpecXmlUtils.encodeStringAttribute(resBuf, "metatype", signed ? "int" : "uint");
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "size", sz);
resBuf.append('>');
}
else if (type instanceof AbstractFloatDataType) {
appendNameIdAttributes(resBuf, origType);
appendNameIdAttributes(resBuf, type);
SpecXmlUtils.encodeStringAttribute(resBuf, "metatype", "float");
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "size", type.getLength());
resBuf.append('>');
@ -597,7 +591,7 @@ public class PcodeDataTypeManager {
sz = size;
isVarLength = true;
}
appendNameIdAttributes(resBuf, origType);
appendNameIdAttributes(resBuf, type);
if (sz < 16) {
SpecXmlUtils.encodeStringAttribute(resBuf, "metatype", "unknown");
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "size", sz);
@ -613,6 +607,7 @@ public class PcodeDataTypeManager {
resBuf.append('>');
}
}
resBuf.append("</type>");
return resBuf.toString();
}
@ -633,27 +628,36 @@ public class PcodeDataTypeManager {
/**
* Build an XML document string representing the type information for a data type
*
* @param resBuf is the stream to append the document to
* @param type data type to build XML for
* @param size size of the data type
*
* @return XML string document
*/
public StringBuilder buildType(DataType type, int size) {
public void buildType(StringBuilder resBuf, DataType type, int size) {
if (type != null && type.getDataTypeManager() != progDataTypes) {
type = type.clone(progDataTypes);
}
StringBuilder resBuf = new StringBuilder();
if ((type instanceof VoidDataType) || (type == null)) {
return resBuf.append("<void/>");
resBuf.append("<void/>");
return;
}
resBuf.append("<type");
resBuf.append(buildTypeInternal(type, size));
resBuf.append("</type>");
return resBuf;
else if (type instanceof TypeDef) {
resBuf.append("<def");
appendNameIdAttributes(resBuf, type);
resBuf.append('>');
DataType refType = ((TypeDef) type).getDataType();
int sz = refType.getLength();
if (sz <= 0) {
sz = size;
}
buildTypeRef(resBuf, refType, sz);
resBuf.append("</def>");
return;
}
buildTypeInternal(resBuf, type, size);
}
/**
* Build an XML document string representing the Structure or Typedef to Structure that has
* Build an XML document string representing the Structure that has
* its size reported as zero.
*
* @param type data type to build XML for
@ -662,8 +666,7 @@ public class PcodeDataTypeManager {
*/
public StringBuilder buildStructTypeZeroSizeOveride(DataType type) {
StringBuilder resBuf = new StringBuilder();
if (!((type instanceof Structure) || ((type instanceof TypeDef) &&
(((TypeDef) type).getBaseDataType() instanceof Structure)))) {
if (!(type instanceof Structure)) {
return resBuf; //empty. Could throw AssertException.
}
resBuf.append("<type");