diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDB.java index 7bfdd477a4..712cfe7a57 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArrayDB.java @@ -57,7 +57,7 @@ class ArrayDB extends DataTypeDB implements Array { @Override public Class getValueClass(Settings settings) { - return DataTypeUtilities.getArrayValueClass(this, settings); + return getArrayValueClass(settings); } @Override @@ -354,18 +354,13 @@ class ArrayDB extends DataTypeDB implements Array { @Override public String getDefaultLabelPrefix(MemBuffer buf, Settings settings, int len, DataTypeDisplayOptions options) { - String prefix = - ArrayStringable.getArrayStringableLabelPrefix(this, buf, settings, len, options); - return prefix != null ? prefix : super.getDefaultLabelPrefix(buf, settings, len, options); + return getArrayDefaultLabelPrefix(buf, settings, len, options); } @Override public String getDefaultOffcutLabelPrefix(MemBuffer buf, Settings settings, int len, DataTypeDisplayOptions options, int offcutLength) { - String prefix = ArrayStringable.getArrayStringableOffcutLabelPrefix(this, buf, settings, - len, options, offcutLength); - return prefix != null ? prefix - : super.getDefaultOffcutLabelPrefix(buf, settings, len, options, offcutLength); + return getArrayDefaultOffcutLabelPrefix(buf, settings, len, options, offcutLength); } @Override @@ -411,11 +406,11 @@ class ArrayDB extends DataTypeDB implements Array { @Override public Object getValue(MemBuffer buf, Settings settings, int length) { - return DataTypeUtilities.getArrayValue(this, buf, settings, length); + return getArrayValue(buf, settings, length); } @Override public String getRepresentation(MemBuffer buf, Settings settings, int length) { - return DataTypeUtilities.getArrayRepresentation(this, buf, settings, length); + return getArrayRepresentation(buf, settings, length); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeUtilities.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeUtilities.java index 27845d4883..2478d67fea 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeUtilities.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeUtilities.java @@ -24,8 +24,6 @@ import ghidra.program.model.address.GlobalNamespace; import ghidra.program.model.data.*; import ghidra.program.model.data.Enum; import ghidra.program.model.listing.Library; -import ghidra.program.model.mem.MemBuffer; -import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.symbol.Namespace; import ghidra.util.UniversalID; import ghidra.util.exception.AssertException; @@ -319,87 +317,6 @@ public class DataTypeUtilities { return buf.toString(); } - /** - * Get the value object which corresponds to an array in memory. This will either be a - * String for the ArrayStringable case or null. - * @param arrayDt array data type - * @param buf data buffer - * @param settings data settings - * @param length length of array - * @return a String if it is an array of chars; otherwise null. - */ - public static Object getArrayValue(Array arrayDt, MemBuffer buf, Settings settings, - int length) { - if (!buf.getMemory().getAllInitializedAddressSet().contains(buf.getAddress())) { - return null; - } - ArrayStringable as = ArrayStringable.getArrayStringable(arrayDt.getDataType()); - Object value = (as != null) ? as.getArrayString(buf, settings, length) : null; - - return value; - // TODO - // For large array it is not scalable to create a java array object. Perhaps - // we could create a GhidraArray that can dish out objects. -// DataType dt = arrayDt.getDataType(); -// Class valueClass = dt.getValueClass(settings); -// if (valueClass != null) { -// int count = arrayDt.getNumElements(); -// int elementLength = arrayDt.getElementLength(); -// WrappedMemBuffer wrappedBuffer = new WrappedMemBuffer(buf, 0); -// Object[] array = (Object[]) java.lang.reflect.Array.newInstance(valueClass, count); -// for (int i = 0; i < count; i++) { -// wrappedBuffer.setBaseOffset(i * elementLength); -// array[i] = dt.getValue(wrappedBuffer, settings, elementLength); -// } -// return array; -// } - } - - /** - * Get the representation which corresponds to an array in memory. This will either be a - * String for the ArrayStringable case or the empty string if it is not. - * - * @param arrayDt array data type - * @param buf data buffer - * @param settings data settings - * @param length length of array - * @return a String if it is an array of chars; otherwise empty string, never null. - */ - public static String getArrayRepresentation(Array arrayDt, MemBuffer buf, Settings settings, - int length) { - try { - buf.getByte(0); // test for uninitialized memory - ArrayStringable as = ArrayStringable.getArrayStringable(arrayDt.getDataType()); - String value = (as != null) ? as.getArrayRepresentation(buf, settings, length) : null; - return (value != null) ? value : ""; - } - catch (MemoryAccessException e) { - // ignore - } - return ""; - } - - /** - * Get the value Class of a specific arrayDt with settings - * ( see {@link #getArrayValueClass(Array, Settings)} ). - * @param settings the relevant settings to use or null for default. - * @return Class of the value to be returned by the array or null if it can vary - * or is unspecified (String or Array class will be returned). - */ - public static Class getArrayValueClass(Array arrayDt, Settings settings) { - DataType dt = arrayDt.getDataType(); - if (dt instanceof TypeDef) { - dt = ((TypeDef) dt).getBaseDataType(); - } - if (dt instanceof ArrayStringable) { - if (((ArrayStringable) dt).hasStringValue(settings)) { - return String.class; - } - } - Class valueClass = dt.getValueClass(settings); - return valueClass != null ? Array.class : null; - } - /** * Create a data type category path derived from the specified namespace and rooted from * the specified baseCategory diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractIntegerDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractIntegerDataType.java index 26751b36e9..815de73af5 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractIntegerDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractIntegerDataType.java @@ -330,25 +330,25 @@ public abstract class AbstractIntegerDataType extends BuiltIn implements ArraySt @Override public String getArrayDefaultLabelPrefix(MemBuffer buf, Settings settings, int len, DataTypeDisplayOptions options) { - if (!hasStringValue(settings)) { - return null; + if (hasStringValue(settings) && buf.isInitializedMemory()) { + return new StringDataInstance(this, settings, buf, len).getLabel( + AbstractStringDataType.DEFAULT_ABBREV_PREFIX + "_", + AbstractStringDataType.DEFAULT_LABEL_PREFIX, AbstractStringDataType.DEFAULT_LABEL, + options); } - return new StringDataInstance(this, settings, buf, len).getLabel( - AbstractStringDataType.DEFAULT_ABBREV_PREFIX + "_", - AbstractStringDataType.DEFAULT_LABEL_PREFIX, AbstractStringDataType.DEFAULT_LABEL, - options); + return null; } @Override public String getArrayDefaultOffcutLabelPrefix(MemBuffer buf, Settings settings, int len, DataTypeDisplayOptions options, int offcutOffset) { - if (!hasStringValue(settings)) { - return null; + if (hasStringValue(settings) && buf.isInitializedMemory()) { + return new StringDataInstance(this, settings, buf, len).getOffcutLabelString( + AbstractStringDataType.DEFAULT_ABBREV_PREFIX + "_", + AbstractStringDataType.DEFAULT_LABEL_PREFIX, AbstractStringDataType.DEFAULT_LABEL, + options, offcutOffset); } - return new StringDataInstance(this, settings, buf, len).getOffcutLabelString( - AbstractStringDataType.DEFAULT_ABBREV_PREFIX + "_", - AbstractStringDataType.DEFAULT_LABEL_PREFIX, AbstractStringDataType.DEFAULT_LABEL, - options, offcutOffset); + return null; } /** diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Array.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Array.java index 45ce05379b..40c3047b3f 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Array.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Array.java @@ -15,6 +15,9 @@ */ package ghidra.program.model.data; +import ghidra.docking.settings.Settings; +import ghidra.program.model.mem.MemBuffer; + /** * Array interface */ @@ -40,4 +43,129 @@ public interface Array extends DataType { */ DataType getDataType(); + /** + * Get the appropriate string to use as the label prefix + * for an array, taking into account the actual data at the memory location. + *

+ * See also {@link #getDefaultLabelPrefix()} + * + * @param buf memory buffer containing the bytes. + * @param settings the Settings object + * @param length the length of the data. + * @param options options for how to format the default label prefix. + * @return the label prefix or null if not applicable + */ + default public String getArrayDefaultLabelPrefix(MemBuffer buf, Settings settings, int len, + DataTypeDisplayOptions options) { + ArrayStringable stringableElementType = ArrayStringable.getArrayStringable(getDataType()); + String prefix = (stringableElementType != null) + ? stringableElementType.getArrayDefaultLabelPrefix(buf, settings, len, options) + : null; + return (prefix != null) ? prefix : getDefaultLabelPrefix(); + } + + /** + * Get the appropriate string to use as the offcut label prefix for an array, taking into + * account the actual data at the memory location. + *

+ * See also {@link #getDefaultLabelPrefix()} + * + * @param buf memory buffer containing the bytes. + * @param settings the Settings object + * @param length the length of the data. + * @param options options for how to format the default label prefix. + * @param offcutLength offcut offset from start of buf + * @return the offcut label prefix or null if not applicable + */ + default public String getArrayDefaultOffcutLabelPrefix(MemBuffer buf, Settings settings, + int len, DataTypeDisplayOptions options, int offcutLength) { + + ArrayStringable stringableElementType = ArrayStringable.getArrayStringable(getDataType()); + String prefix = (stringableElementType != null) + ? stringableElementType.getArrayDefaultOffcutLabelPrefix(buf, settings, len, + options, offcutLength) + : null; + return (prefix != null) ? prefix : getDefaultLabelPrefix(buf, settings, len, options); + } + + /** + * Get the representation which corresponds to an array in memory. This will either be a + * String for the ArrayStringable case, "??" for uninitialized data, + * or the empty string if it is not. + * + * @param buf data buffer + * @param settings data settings + * @param length length of array + * @return a String if it is an array of chars; otherwise empty string, never null. + */ + default public String getArrayRepresentation(MemBuffer buf, Settings settings, int length) { + if (!buf.isInitializedMemory()) { + return StringDataInstance.UNKNOWN; + } + ArrayStringable stringableElementType = ArrayStringable.getArrayStringable(getDataType()); + String value = + (stringableElementType != null && stringableElementType.hasStringValue(settings)) + ? new StringDataInstance(stringableElementType, settings, buf, + length).getStringRepresentation() + : null; + return (value != null) ? value : ""; + } + + /** + * Get the value object which corresponds to an array in memory. This will either be a + * String for the ArrayStringable case or null. + * + * @param buf data buffer + * @param settings data settings + * @param length length of array + * @return a String if it is an array of chars; otherwise null. + */ + default Object getArrayValue(MemBuffer buf, Settings settings, int length) { + if (!buf.getMemory().getAllInitializedAddressSet().contains(buf.getAddress())) { + return null; + } + ArrayStringable as = ArrayStringable.getArrayStringable(getDataType()); + Object value = (as != null) ? as.getArrayString(buf, settings, length) : null; + + return value; + // TODO + // For large array it is not scalable to create a java array object. Perhaps + // we could create a GhidraArray that can dish out objects. +// DataType dt = arrayDt.getDataType(); +// Class valueClass = dt.getValueClass(settings); +// if (valueClass != null) { +// int count = arrayDt.getNumElements(); +// int elementLength = arrayDt.getElementLength(); +// WrappedMemBuffer wrappedBuffer = new WrappedMemBuffer(buf, 0); +// Object[] array = (Object[]) java.lang.reflect.Array.newInstance(valueClass, count); +// for (int i = 0; i < count; i++) { +// wrappedBuffer.setBaseOffset(i * elementLength); +// array[i] = dt.getValue(wrappedBuffer, settings, elementLength); +// } +// return array; +// } + } + + /** + * Get the value Class of a specific arrayDt with settings + * ( see {@link #getArrayValueClass(Array, Settings)} ). + * + * @param settings the relevant settings to use or null for default. + * @return Class of the value to be returned by the array or null if it can vary + * or is unspecified (String or Array class will be returned). + */ + default public Class getArrayValueClass(Settings settings) { + DataType dt = getDataType(); + if (dt instanceof TypeDef) { + dt = ((TypeDef) dt).getBaseDataType(); + } + if (dt instanceof ArrayStringable) { + if (((ArrayStringable) dt).hasStringValue(settings)) { + return String.class; + } + } + Class valueClass = dt.getValueClass(settings); + return valueClass != null ? Array.class : null; + } + } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ArrayDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ArrayDataType.java index 0d436d7ea9..ce81f3927b 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ArrayDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ArrayDataType.java @@ -165,7 +165,7 @@ public class ArrayDataType extends DataTypeImpl implements Array { @Override public Class getValueClass(Settings settings) { - return DataTypeUtilities.getArrayValueClass(this, settings); + return getArrayValueClass(settings); } @Override @@ -253,18 +253,13 @@ public class ArrayDataType extends DataTypeImpl implements Array { @Override public String getDefaultLabelPrefix(MemBuffer buf, Settings settings, int len, DataTypeDisplayOptions options) { - String prefix = - ArrayStringable.getArrayStringableLabelPrefix(this, buf, settings, len, options); - return prefix != null ? prefix : super.getDefaultLabelPrefix(buf, settings, len, options); + return getArrayDefaultLabelPrefix(buf, settings, len, options); } @Override public String getDefaultOffcutLabelPrefix(MemBuffer buf, Settings settings, int len, DataTypeDisplayOptions options, int offcutLength) { - String prefix = ArrayStringable.getArrayStringableOffcutLabelPrefix(this, buf, settings, - len, options, offcutLength); - return prefix != null ? prefix - : super.getDefaultOffcutLabelPrefix(buf, settings, len, options, offcutLength); + return getArrayDefaultOffcutLabelPrefix(buf, settings, len, options, offcutLength); } @Override @@ -274,12 +269,12 @@ public class ArrayDataType extends DataTypeImpl implements Array { @Override public Object getValue(MemBuffer buf, Settings settings, int length) { - return DataTypeUtilities.getArrayValue(this, buf, settings, length); + return getArrayValue(buf, settings, length); } @Override public String getRepresentation(MemBuffer buf, Settings settings, int length) { - return DataTypeUtilities.getArrayRepresentation(this, buf, settings, length); + return getArrayRepresentation(buf, settings, length); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ArrayStringable.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ArrayStringable.java index 618ee851f4..622854e304 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ArrayStringable.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ArrayStringable.java @@ -16,7 +16,6 @@ package ghidra.program.model.data; import ghidra.docking.settings.Settings; -import ghidra.program.model.listing.Data; import ghidra.program.model.mem.MemBuffer; /** @@ -37,23 +36,6 @@ public interface ArrayStringable extends DataType { */ public boolean hasStringValue(Settings settings); - /** - * Returns a {@link StringDataInstance} representing this ArrayStringable's contents. - * - *

- * @param buf {@link MemBuffer} containing the data bytes. - * @param settings {@link Settings} object containing settings, usually the {@link Data} - * element. - * @param length number of bytes that this data object contains (ie. how big was the array) - * @return a new {@link StringDataInstance} representing this ArrayStringable's contents, - * never NULL. See {@link StringDataInstance#NULL_INSTANCE}. - */ - public default StringDataInstance getStringDataInstance(MemBuffer buf, Settings settings, - int length) { - return hasStringValue(settings) ? new StringDataInstance(this, settings, buf, length) - : StringDataInstance.NULL_INSTANCE; - } - /** * For cases where an array of this type exists, get the array value as a String. * When data corresponds to character data it should generally be expressed as a string. @@ -64,19 +46,10 @@ public interface ArrayStringable extends DataType { * @return array value expressed as a string or null if data is not character data */ public default String getArrayString(MemBuffer buf, Settings settings, int length) { - return getStringDataInstance(buf, settings, length).getStringValue(); - } - - /** - * For cases where an array of this type exists, get the representation string which - * corresponds to the array (example: String for an array of chars). - * @param buf memory buffer containing the bytes. - * @param settings the Settings object - * @param length the length of the data. - * @return array representation or null of an array representation is not supported. - */ - public default String getArrayRepresentation(MemBuffer buf, Settings settings, int length) { - return getStringDataInstance(buf, settings, length).getStringRepresentation(); + if (hasStringValue(settings) && buf.isInitializedMemory()) { + return new StringDataInstance(this, settings, buf, length).getStringValue(); + } + return null; } /** @@ -126,40 +99,4 @@ public interface ArrayStringable extends DataType { return (dt instanceof ArrayStringable) ? (ArrayStringable) dt : null; } - /** - * Get the appropriate string to use as the label prefix - * for an array which corresponds to an ArrayStringable - * element data type. - * @param arrayDt array data type - * @param buf memory buffer containing the bytes. - * @param settings the Settings object - * @param length the length of the data. - * @param options options for how to format the default label prefix. - * @return the ArrayStringable label prefix or null if not applicable - */ - public static String getArrayStringableLabelPrefix(Array arrayDt, MemBuffer buf, - Settings settings, int len, DataTypeDisplayOptions options) { - ArrayStringable as = getArrayStringable(arrayDt.getDataType()); - return (as != null) ? as.getArrayDefaultLabelPrefix(buf, settings, len, options) : null; - } - - /** - * Get the appropriate string to use as the offcut label prefix - * for an array which corresponds to an ArrayStringable - * element data type. - * @param arrayDt array data type - * @param buf memory buffer containing the bytes. - * @param settings the Settings object - * @param length the length of the data. - * @param options options for how to format the default label prefix. - * @param offcutLength offcut offset from start of buf - * @return the ArrayStringable offcut label prefix or null if not applicable - */ - public static String getArrayStringableOffcutLabelPrefix(Array arrayDt, MemBuffer buf, - Settings settings, int len, DataTypeDisplayOptions options, int offcutLength) { - ArrayStringable as = getArrayStringable(arrayDt.getDataType()); - return (as != null) - ? as.getArrayDefaultOffcutLabelPrefix(buf, settings, len, options, offcutLength) - : null; - } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StringDataInstance.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StringDataInstance.java index 4cb29b279d..63fb494142 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StringDataInstance.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StringDataInstance.java @@ -51,7 +51,7 @@ public class StringDataInstance { * @return boolean true if string data. */ public static boolean isString(Data data) { - if (data == null) { + if (data == null || !data.isInitializedMemory()) { return false; } DataType dt = data.getBaseDataType(); @@ -89,36 +89,38 @@ public class StringDataInstance { return ((AbstractStringDataType) dt).getStringDataInstance(data, data, data.getLength()); } - if (dt instanceof Array) { + if (dt instanceof Array && !data.isInitializedMemory()) { ArrayStringable arrayStringable = ArrayStringable.getArrayStringable(((Array) dt).getDataType()); - return arrayStringable.getStringDataInstance(data, data, data.getLength()); + if (arrayStringable != null && arrayStringable.hasStringValue(data)) { + return new StringDataInstance(arrayStringable, data, data, data.getLength()); + } } return NULL_INSTANCE; + } /** * Returns a new {@link StringDataInstance} using the bytes in the MemBuffer. *

- * @param stringDataType {@link DataType} of the bytes in the buffer. + * @param dataType {@link DataType} of the bytes in the buffer. * @param buf memory buffer containing the bytes. * @param settings the Settings object * @param length the length of the data. * @return new {@link StringDataInstance}, never NULL. See {@link #NULL_INSTANCE}. */ - public static StringDataInstance getStringDataInstance(DataType stringDataType, MemBuffer buf, + public static StringDataInstance getStringDataInstance(DataType dataType, MemBuffer buf, Settings settings, int length) { - if (stringDataType instanceof AbstractStringDataType) { - return ((AbstractStringDataType) stringDataType).getStringDataInstance(buf, settings, - length); + if (dataType instanceof AbstractStringDataType) { + return ((AbstractStringDataType) dataType).getStringDataInstance(buf, settings, length); } - if (stringDataType instanceof Array && - ((Array) stringDataType).getDataType() instanceof ArrayStringable) { - stringDataType = ((Array) stringDataType).getDataType(); + if (dataType instanceof Array) { + dataType = ArrayStringable.getArrayStringable(((Array) dataType).getDataType()); } - if (stringDataType instanceof ArrayStringable && - ((ArrayStringable) stringDataType).hasStringValue(settings)) { - return ((ArrayStringable) stringDataType).getStringDataInstance(buf, settings, length); + if (dataType instanceof ArrayStringable && + ((ArrayStringable) dataType).hasStringValue(settings) && buf.isInitializedMemory()) { + + return new StringDataInstance(dataType, settings, buf, length); } return NULL_INSTANCE; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemBuffer.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemBuffer.java index 9f70c2bed5..e7ca401843 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemBuffer.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemBuffer.java @@ -51,6 +51,24 @@ import ghidra.program.model.address.Address; */ public interface MemBuffer { + /** + * Returns true if this buffer's starting address has valid data. + * + * @return boolean true if first byte of memory buffer can be read + */ + public default boolean isInitializedMemory() { + // TODO: possible alternate method of testing + //return getMemory().getAllInitializedAddressSet().contains(getAddress()); + try { + getByte(0); // test for uninitialized memory + return true; + } + catch (MemoryAccessException e) { + // ignore + } + return false; + } + /** * Get one byte from memory at the current position plus offset. *