mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
GT-2715 Fix stringable arrays label text generation with uninit mem.
(#272) Check for uninitialized memory before treating as a string.
This commit is contained in:
parent
26b2dfef94
commit
dd7ffda876
8 changed files with 188 additions and 196 deletions
|
@ -57,7 +57,7 @@ class ArrayDB extends DataTypeDB implements Array {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<?> getValueClass(Settings settings) {
|
public Class<?> getValueClass(Settings settings) {
|
||||||
return DataTypeUtilities.getArrayValueClass(this, settings);
|
return getArrayValueClass(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -354,18 +354,13 @@ class ArrayDB extends DataTypeDB implements Array {
|
||||||
@Override
|
@Override
|
||||||
public String getDefaultLabelPrefix(MemBuffer buf, Settings settings, int len,
|
public String getDefaultLabelPrefix(MemBuffer buf, Settings settings, int len,
|
||||||
DataTypeDisplayOptions options) {
|
DataTypeDisplayOptions options) {
|
||||||
String prefix =
|
return getArrayDefaultLabelPrefix(buf, settings, len, options);
|
||||||
ArrayStringable.getArrayStringableLabelPrefix(this, buf, settings, len, options);
|
|
||||||
return prefix != null ? prefix : super.getDefaultLabelPrefix(buf, settings, len, options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDefaultOffcutLabelPrefix(MemBuffer buf, Settings settings, int len,
|
public String getDefaultOffcutLabelPrefix(MemBuffer buf, Settings settings, int len,
|
||||||
DataTypeDisplayOptions options, int offcutLength) {
|
DataTypeDisplayOptions options, int offcutLength) {
|
||||||
String prefix = ArrayStringable.getArrayStringableOffcutLabelPrefix(this, buf, settings,
|
return getArrayDefaultOffcutLabelPrefix(buf, settings, len, options, offcutLength);
|
||||||
len, options, offcutLength);
|
|
||||||
return prefix != null ? prefix
|
|
||||||
: super.getDefaultOffcutLabelPrefix(buf, settings, len, options, offcutLength);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -411,11 +406,11 @@ class ArrayDB extends DataTypeDB implements Array {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getValue(MemBuffer buf, Settings settings, int length) {
|
public Object getValue(MemBuffer buf, Settings settings, int length) {
|
||||||
return DataTypeUtilities.getArrayValue(this, buf, settings, length);
|
return getArrayValue(buf, settings, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
|
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
|
||||||
return DataTypeUtilities.getArrayRepresentation(this, buf, settings, length);
|
return getArrayRepresentation(buf, settings, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,6 @@ import ghidra.program.model.address.GlobalNamespace;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.data.Enum;
|
import ghidra.program.model.data.Enum;
|
||||||
import ghidra.program.model.listing.Library;
|
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.program.model.symbol.Namespace;
|
||||||
import ghidra.util.UniversalID;
|
import ghidra.util.UniversalID;
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
|
@ -319,87 +317,6 @@ public class DataTypeUtilities {
|
||||||
return buf.toString();
|
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
|
* Create a data type category path derived from the specified namespace and rooted from
|
||||||
* the specified baseCategory
|
* the specified baseCategory
|
||||||
|
|
|
@ -330,25 +330,25 @@ public abstract class AbstractIntegerDataType extends BuiltIn implements ArraySt
|
||||||
@Override
|
@Override
|
||||||
public String getArrayDefaultLabelPrefix(MemBuffer buf, Settings settings, int len,
|
public String getArrayDefaultLabelPrefix(MemBuffer buf, Settings settings, int len,
|
||||||
DataTypeDisplayOptions options) {
|
DataTypeDisplayOptions options) {
|
||||||
if (!hasStringValue(settings)) {
|
if (hasStringValue(settings) && buf.isInitializedMemory()) {
|
||||||
return null;
|
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(
|
return null;
|
||||||
AbstractStringDataType.DEFAULT_ABBREV_PREFIX + "_",
|
|
||||||
AbstractStringDataType.DEFAULT_LABEL_PREFIX, AbstractStringDataType.DEFAULT_LABEL,
|
|
||||||
options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getArrayDefaultOffcutLabelPrefix(MemBuffer buf, Settings settings, int len,
|
public String getArrayDefaultOffcutLabelPrefix(MemBuffer buf, Settings settings, int len,
|
||||||
DataTypeDisplayOptions options, int offcutOffset) {
|
DataTypeDisplayOptions options, int offcutOffset) {
|
||||||
if (!hasStringValue(settings)) {
|
if (hasStringValue(settings) && buf.isInitializedMemory()) {
|
||||||
return null;
|
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(
|
return null;
|
||||||
AbstractStringDataType.DEFAULT_ABBREV_PREFIX + "_",
|
|
||||||
AbstractStringDataType.DEFAULT_LABEL_PREFIX, AbstractStringDataType.DEFAULT_LABEL,
|
|
||||||
options, offcutOffset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -15,6 +15,9 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.program.model.data;
|
package ghidra.program.model.data;
|
||||||
|
|
||||||
|
import ghidra.docking.settings.Settings;
|
||||||
|
import ghidra.program.model.mem.MemBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array interface
|
* Array interface
|
||||||
*/
|
*/
|
||||||
|
@ -40,4 +43,129 @@ public interface Array extends DataType {
|
||||||
*/
|
*/
|
||||||
DataType getDataType();
|
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.
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,7 +165,7 @@ public class ArrayDataType extends DataTypeImpl implements Array {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<?> getValueClass(Settings settings) {
|
public Class<?> getValueClass(Settings settings) {
|
||||||
return DataTypeUtilities.getArrayValueClass(this, settings);
|
return getArrayValueClass(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -253,18 +253,13 @@ public class ArrayDataType extends DataTypeImpl implements Array {
|
||||||
@Override
|
@Override
|
||||||
public String getDefaultLabelPrefix(MemBuffer buf, Settings settings, int len,
|
public String getDefaultLabelPrefix(MemBuffer buf, Settings settings, int len,
|
||||||
DataTypeDisplayOptions options) {
|
DataTypeDisplayOptions options) {
|
||||||
String prefix =
|
return getArrayDefaultLabelPrefix(buf, settings, len, options);
|
||||||
ArrayStringable.getArrayStringableLabelPrefix(this, buf, settings, len, options);
|
|
||||||
return prefix != null ? prefix : super.getDefaultLabelPrefix(buf, settings, len, options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDefaultOffcutLabelPrefix(MemBuffer buf, Settings settings, int len,
|
public String getDefaultOffcutLabelPrefix(MemBuffer buf, Settings settings, int len,
|
||||||
DataTypeDisplayOptions options, int offcutLength) {
|
DataTypeDisplayOptions options, int offcutLength) {
|
||||||
String prefix = ArrayStringable.getArrayStringableOffcutLabelPrefix(this, buf, settings,
|
return getArrayDefaultOffcutLabelPrefix(buf, settings, len, options, offcutLength);
|
||||||
len, options, offcutLength);
|
|
||||||
return prefix != null ? prefix
|
|
||||||
: super.getDefaultOffcutLabelPrefix(buf, settings, len, options, offcutLength);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -274,12 +269,12 @@ public class ArrayDataType extends DataTypeImpl implements Array {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getValue(MemBuffer buf, Settings settings, int length) {
|
public Object getValue(MemBuffer buf, Settings settings, int length) {
|
||||||
return DataTypeUtilities.getArrayValue(this, buf, settings, length);
|
return getArrayValue(buf, settings, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
|
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
|
||||||
return DataTypeUtilities.getArrayRepresentation(this, buf, settings, length);
|
return getArrayRepresentation(buf, settings, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
package ghidra.program.model.data;
|
package ghidra.program.model.data;
|
||||||
|
|
||||||
import ghidra.docking.settings.Settings;
|
import ghidra.docking.settings.Settings;
|
||||||
import ghidra.program.model.listing.Data;
|
|
||||||
import ghidra.program.model.mem.MemBuffer;
|
import ghidra.program.model.mem.MemBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,23 +36,6 @@ public interface ArrayStringable extends DataType {
|
||||||
*/
|
*/
|
||||||
public boolean hasStringValue(Settings settings);
|
public boolean hasStringValue(Settings settings);
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a {@link StringDataInstance} representing this ArrayStringable's contents.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* @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.
|
* 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.
|
* 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
|
* @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) {
|
public default String getArrayString(MemBuffer buf, Settings settings, int length) {
|
||||||
return getStringDataInstance(buf, settings, length).getStringValue();
|
if (hasStringValue(settings) && buf.isInitializedMemory()) {
|
||||||
}
|
return new StringDataInstance(this, settings, buf, length).getStringValue();
|
||||||
|
}
|
||||||
/**
|
return null;
|
||||||
* 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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -126,40 +99,4 @@ public interface ArrayStringable extends DataType {
|
||||||
return (dt instanceof ArrayStringable) ? (ArrayStringable) dt : null;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ public class StringDataInstance {
|
||||||
* @return boolean true if string data.
|
* @return boolean true if string data.
|
||||||
*/
|
*/
|
||||||
public static boolean isString(Data data) {
|
public static boolean isString(Data data) {
|
||||||
if (data == null) {
|
if (data == null || !data.isInitializedMemory()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
DataType dt = data.getBaseDataType();
|
DataType dt = data.getBaseDataType();
|
||||||
|
@ -89,36 +89,38 @@ public class StringDataInstance {
|
||||||
return ((AbstractStringDataType) dt).getStringDataInstance(data, data,
|
return ((AbstractStringDataType) dt).getStringDataInstance(data, data,
|
||||||
data.getLength());
|
data.getLength());
|
||||||
}
|
}
|
||||||
if (dt instanceof Array) {
|
if (dt instanceof Array && !data.isInitializedMemory()) {
|
||||||
ArrayStringable arrayStringable =
|
ArrayStringable arrayStringable =
|
||||||
ArrayStringable.getArrayStringable(((Array) dt).getDataType());
|
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;
|
return NULL_INSTANCE;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new {@link StringDataInstance} using the bytes in the MemBuffer.
|
* Returns a new {@link StringDataInstance} using the bytes in the MemBuffer.
|
||||||
* <p>
|
* <p>
|
||||||
* @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 buf memory buffer containing the bytes.
|
||||||
* @param settings the Settings object
|
* @param settings the Settings object
|
||||||
* @param length the length of the data.
|
* @param length the length of the data.
|
||||||
* @return new {@link StringDataInstance}, never NULL. See {@link #NULL_INSTANCE}.
|
* @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) {
|
Settings settings, int length) {
|
||||||
if (stringDataType instanceof AbstractStringDataType) {
|
if (dataType instanceof AbstractStringDataType) {
|
||||||
return ((AbstractStringDataType) stringDataType).getStringDataInstance(buf, settings,
|
return ((AbstractStringDataType) dataType).getStringDataInstance(buf, settings, length);
|
||||||
length);
|
|
||||||
}
|
}
|
||||||
if (stringDataType instanceof Array &&
|
if (dataType instanceof Array) {
|
||||||
((Array) stringDataType).getDataType() instanceof ArrayStringable) {
|
dataType = ArrayStringable.getArrayStringable(((Array) dataType).getDataType());
|
||||||
stringDataType = ((Array) stringDataType).getDataType();
|
|
||||||
}
|
}
|
||||||
if (stringDataType instanceof ArrayStringable &&
|
if (dataType instanceof ArrayStringable &&
|
||||||
((ArrayStringable) stringDataType).hasStringValue(settings)) {
|
((ArrayStringable) dataType).hasStringValue(settings) && buf.isInitializedMemory()) {
|
||||||
return ((ArrayStringable) stringDataType).getStringDataInstance(buf, settings, length);
|
|
||||||
|
return new StringDataInstance(dataType, settings, buf, length);
|
||||||
}
|
}
|
||||||
return NULL_INSTANCE;
|
return NULL_INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,24 @@ import ghidra.program.model.address.Address;
|
||||||
*/
|
*/
|
||||||
public interface MemBuffer {
|
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.
|
* Get one byte from memory at the current position plus offset.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue