mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Merge branch 'GP-1379_ghidra1_FloatDataTypeValues' (Closes #4853)
This commit is contained in:
commit
6d85c6cbc1
116 changed files with 2122 additions and 1757 deletions
|
@ -57,7 +57,8 @@ public class ProgramProviderContext implements DataTypeProviderContext {
|
|||
}
|
||||
|
||||
DataType dt = data.getDataType();
|
||||
int length = data.getLength();
|
||||
int length = DataTypeComponentImpl.getPreferredComponentLength(dt,
|
||||
Math.max(data.getLength(), dt.getAlignedLength()));
|
||||
String label = null;
|
||||
Symbol symbol = data.getPrimarySymbol();
|
||||
if (symbol != null && !symbol.isDynamic()) {
|
||||
|
|
|
@ -15,8 +15,9 @@
|
|||
*/
|
||||
package ghidra.pcode.floatformat;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.math.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An IEEE 754 floating point class.
|
||||
|
@ -31,8 +32,20 @@ import java.math.BigInteger;
|
|||
*
|
||||
* <p>Operations compute exact result then round to nearest even.
|
||||
*/
|
||||
public strictfp class BigFloat implements Comparable<BigFloat> {
|
||||
final int fracbits; // there are fracbits+1 significant bits.
|
||||
public class BigFloat implements Comparable<BigFloat> {
|
||||
|
||||
public static final String INFINITY = "Infinity";
|
||||
public static final String POSITIVE_INFINITY = "+" + INFINITY;
|
||||
public static final String NEGATIVE_INFINITY = "-" + INFINITY;
|
||||
public static final String NAN = "NaN";
|
||||
|
||||
private static final int INFINITE_SCALE = -(64 * 1024);
|
||||
public static final BigDecimal BIG_POSITIVE_INFINITY =
|
||||
new BigDecimal(BigInteger.ONE, INFINITE_SCALE);
|
||||
public static final BigDecimal BIG_NEGATIVE_INFINITY =
|
||||
(new BigDecimal(BigInteger.ONE, INFINITE_SCALE)).negate();
|
||||
|
||||
final int fracbits; // number of significant mantissa bits including implied msb if relavent
|
||||
final int expbits; // # bits used for exponent
|
||||
|
||||
final int maxScale;
|
||||
|
@ -40,19 +53,22 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
|
||||
FloatKind kind;
|
||||
|
||||
// -1, +1
|
||||
int sign;
|
||||
// normal numbers have unscaled.bitLength() = fracbits+1
|
||||
int sign; // -1, +1
|
||||
|
||||
// normal numbers have unscaled.bitLength() = fracbits+1
|
||||
// subnormal numbers have scale=0 and unscaled.bitLength() <= fracbits
|
||||
BigInteger unscaled;
|
||||
int scale;
|
||||
|
||||
private static Map<Integer, MathContext> defaultDisplayContextMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Construct a BigFloat. If kind is FINITE, the value is <code>sign*unscaled*2^(scale-fracbits)</code>.
|
||||
* <p>
|
||||
* NOTE: Requires that normal values are constructed in a normal form as with denormal values.
|
||||
*
|
||||
* @param fracbits number of fractional bits (positive non-zero value)
|
||||
* @param fracbits number of fractional bits (positive non-zero value; includes additional
|
||||
* implied bit if relavent).
|
||||
* @param expbits maximum number of bits in exponent (positive non-zero value)
|
||||
* @param kind the Kind, FINITE, INFINITE, ...
|
||||
* @param sign +1 or -1
|
||||
|
@ -71,8 +87,8 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
this.maxScale = (1 << (expbits - 1)) - 1;
|
||||
this.minScale = 1 - this.maxScale;
|
||||
|
||||
if (unscaled.bitLength() > (fracbits + 1)) {
|
||||
throw new IllegalArgumentException("unscaled value exceeds " + (fracbits + 1) +
|
||||
if (unscaled.bitLength() > fracbits) {
|
||||
throw new IllegalArgumentException("unscaled value exceeds " + fracbits +
|
||||
" bits in length (length=" + unscaled.bitLength() + ")");
|
||||
}
|
||||
if (scale < minScale || scale > maxScale) {
|
||||
|
@ -182,7 +198,7 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
*/
|
||||
public static BigFloat infinity(int fracbits, int expbits, int sign) {
|
||||
return new BigFloat(fracbits, expbits, FloatKind.INFINITE, sign,
|
||||
BigInteger.ONE.shiftLeft(fracbits), (1 << (expbits - 1)) - 1);
|
||||
BigInteger.ONE.shiftLeft(fracbits - 1), (1 << (expbits - 1)) - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -223,7 +239,7 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
* @return {@code true} if this BigFloat is FINITE and normal.
|
||||
*/
|
||||
public boolean isNormal() {
|
||||
return kind == FloatKind.FINITE && unscaled.bitLength() == (fracbits + 1);
|
||||
return kind == FloatKind.FINITE && unscaled.bitLength() == fracbits;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -236,7 +252,7 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
*/
|
||||
public boolean isDenormal() {
|
||||
return kind == FloatKind.FINITE && !unscaled.equals(BigInteger.ZERO) &&
|
||||
unscaled.bitLength() <= fracbits;
|
||||
unscaled.bitLength() < fracbits;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -263,7 +279,7 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
return;
|
||||
}
|
||||
|
||||
int extrabits = Math.max(unscaled.bitLength() - (fracbits + 1), minScale - scale);
|
||||
int extrabits = Math.max(unscaled.bitLength() - fracbits, minScale - scale);
|
||||
|
||||
if (extrabits <= 0) {
|
||||
throw new AssertionError("Rounding with no extra bits of precision");
|
||||
|
@ -279,7 +295,7 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
if (midbitset && (eps || odd)) {
|
||||
unscaled = unscaled.add(BigInteger.ONE);
|
||||
// handle overflowing carry
|
||||
if (unscaled.bitLength() > fracbits + 1) {
|
||||
if (unscaled.bitLength() > fracbits) {
|
||||
assert (unscaled.bitLength() == unscaled.getLowestSetBit() + 1);
|
||||
unscaled = unscaled.shiftRight(1);
|
||||
scale += 1;
|
||||
|
@ -295,14 +311,15 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
if (kind != FloatKind.FINITE || unscaled.signum() == 0) {
|
||||
throw new AssertionError("lead bit of non-finite or zero");
|
||||
}
|
||||
return unscaled.bitLength() - fracbits + scale;
|
||||
return unscaled.bitLength() - fracbits + scale + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* If finite, the returned BigDecimal is exactly equal to this. If not finite, one of the
|
||||
* FloatFormat.BIG_* constants is returned.
|
||||
*
|
||||
* @return a BigDecimal
|
||||
* @return a BigDecimal or null if value is NaN (i.e., {@link FloatKind#QUIET_NAN} or
|
||||
* {@link FloatKind#SIGNALING_NAN}).
|
||||
*/
|
||||
public BigDecimal toBigDecimal() {
|
||||
switch (kind) {
|
||||
|
@ -312,7 +329,7 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
}
|
||||
int unusedBits = Math.max(unscaled.getLowestSetBit(), 0);
|
||||
BigInteger val = unscaled;
|
||||
int iscale = scale - fracbits;
|
||||
int iscale = scale - fracbits + 1;
|
||||
BigDecimal x;
|
||||
if (iscale >= -unusedBits) {
|
||||
x = new BigDecimal(val.shiftLeft(iscale));
|
||||
|
@ -330,11 +347,10 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
}
|
||||
return x;
|
||||
case INFINITE:
|
||||
return sign < 0 ? FloatFormat.BIG_NEGATIVE_INFINITY
|
||||
: FloatFormat.BIG_POSITIVE_INFINITY;
|
||||
return sign < 0 ? BIG_NEGATIVE_INFINITY : BIG_POSITIVE_INFINITY;
|
||||
case QUIET_NAN:
|
||||
case SIGNALING_NAN:
|
||||
return FloatFormat.BIG_NaN;
|
||||
return null;
|
||||
default:
|
||||
throw new AssertionError("unknown BigFloat kind: " + kind);
|
||||
}
|
||||
|
@ -359,15 +375,16 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
String binary;
|
||||
if (this.isNormal()) {
|
||||
binary = "1." + unscaled.toString(2).substring(1);
|
||||
ascale += (unscaled.bitLength() - (fracbits + 1));
|
||||
ascale += (unscaled.bitLength() - fracbits);
|
||||
}
|
||||
else { // subnormal
|
||||
assert (unscaled.bitLength() <= fracbits);
|
||||
assert (unscaled.bitLength() < fracbits);
|
||||
if (unscaled.equals(BigInteger.ZERO)) {
|
||||
return String.format("%s0b0.0", s);
|
||||
}
|
||||
binary =
|
||||
"0." + "0".repeat(fracbits - unscaled.bitLength()) + unscaled.toString(2);
|
||||
"0." + "0".repeat(fracbits - unscaled.bitLength() - 1) +
|
||||
unscaled.toString(2);
|
||||
}
|
||||
binary = binary.replaceAll("0*$", "");
|
||||
if (binary.endsWith(".")) {
|
||||
|
@ -497,7 +514,7 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
// nbits(x) - nbits(y) <= nbits(x/y) <= nbits(x) - nbits(y) + 1
|
||||
// so
|
||||
// this + lshift - other = fracbits+2 =>
|
||||
int lshift = fracbits + 2 + other.unscaled.bitLength() - this.unscaled.bitLength();
|
||||
int lshift = fracbits + 1 + other.unscaled.bitLength() - this.unscaled.bitLength();
|
||||
this.upscale(lshift);
|
||||
|
||||
BigInteger qr[] = this.unscaled.divideAndRemainder(other.unscaled);
|
||||
|
@ -505,7 +522,7 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
BigInteger r = qr[1];
|
||||
|
||||
this.sign *= other.sign;
|
||||
this.scale -= other.scale - fracbits;
|
||||
this.scale -= other.scale - fracbits + 1;
|
||||
this.unscaled = q;
|
||||
this.internalRound(r.signum() != 0);
|
||||
}
|
||||
|
@ -545,9 +562,9 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
// this and other are finite
|
||||
this.sign *= other.sign;
|
||||
this.unscaled = this.unscaled.multiply(other.unscaled);
|
||||
this.scale += other.scale - fracbits;
|
||||
this.scale += other.scale - fracbits + 1;
|
||||
|
||||
this.scaleUpTo(fracbits + 2);
|
||||
this.scaleUpTo(fracbits + 1);
|
||||
this.internalRound(false);
|
||||
}
|
||||
|
||||
|
@ -639,10 +656,10 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
protected void add0(BigFloat other) {
|
||||
int d = this.scale - other.scale;
|
||||
|
||||
if (d > fracbits + 1) {
|
||||
if (d > fracbits) {
|
||||
return;
|
||||
}
|
||||
else if (d < -(fracbits + 1)) {
|
||||
else if (d < -fracbits) {
|
||||
this.copyFrom(other);
|
||||
return;
|
||||
}
|
||||
|
@ -664,7 +681,7 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
this.scale = a.scale - 1;
|
||||
this.unscaled = a.unscaled.shiftLeft(1).add(b.unscaled.shiftRight(d - 1));
|
||||
|
||||
scaleUpTo(fracbits + 2);
|
||||
scaleUpTo(fracbits + 1);
|
||||
internalRound(residue);
|
||||
}
|
||||
|
||||
|
@ -672,10 +689,10 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
protected void sub0(BigFloat other) {
|
||||
int d = this.scale - other.scale;
|
||||
|
||||
if (d > fracbits + 2) {
|
||||
if (d > fracbits + 1) {
|
||||
return;
|
||||
}
|
||||
else if (d < -(fracbits + 2)) {
|
||||
else if (d < -(fracbits + 1)) {
|
||||
this.copyFrom(other);
|
||||
return;
|
||||
}
|
||||
|
@ -710,7 +727,7 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
this.sign *= -1;
|
||||
this.unscaled = this.unscaled.negate();
|
||||
}
|
||||
scaleUpTo(fracbits + 2);
|
||||
scaleUpTo(fracbits + 1);
|
||||
internalRound(residue);
|
||||
}
|
||||
|
||||
|
@ -751,11 +768,11 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
BigInteger bit;
|
||||
|
||||
//// force at least fracbits+2 bits of precision in the result
|
||||
int sigbits = 2 * fracbits + 3;
|
||||
int sigbits = 2 * fracbits + 2;
|
||||
this.scaleUpTo(sigbits);
|
||||
|
||||
// scale+fracbits needs to be even for the sqrt computation
|
||||
if (((scale + fracbits) & 1) != 0) {
|
||||
if (((scale + fracbits - 1) & 1) != 0) {
|
||||
upscale(1);
|
||||
}
|
||||
|
||||
|
@ -778,7 +795,7 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
}
|
||||
|
||||
unscaled = result;
|
||||
scale = (scale + fracbits) / 2;
|
||||
scale = (scale + fracbits - 1) / 2;
|
||||
|
||||
internalRound(residue.signum() != 0);
|
||||
}
|
||||
|
@ -790,7 +807,7 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
makeZero();
|
||||
return;
|
||||
}
|
||||
int nbitsUnderOne = fracbits - scale;
|
||||
int nbitsUnderOne = fracbits - scale - 1;
|
||||
unscaled = unscaled.shiftRight(nbitsUnderOne).shiftLeft(nbitsUnderOne);
|
||||
}
|
||||
|
||||
|
@ -798,7 +815,7 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
private void makeOne() {
|
||||
kind = FloatKind.FINITE;
|
||||
scale = 0;
|
||||
unscaled = BigInteger.ONE.shiftLeft(fracbits);
|
||||
unscaled = BigInteger.ONE.shiftLeft(fracbits - 1);
|
||||
}
|
||||
|
||||
// ceil, ignoring sign
|
||||
|
@ -811,7 +828,7 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
return;
|
||||
}
|
||||
|
||||
int nbitsUnderOne = fracbits - scale;
|
||||
int nbitsUnderOne = fracbits - scale - 1;
|
||||
boolean increment = unscaled.getLowestSetBit() < nbitsUnderOne;
|
||||
unscaled = unscaled.shiftRight(nbitsUnderOne).shiftLeft(nbitsUnderOne);
|
||||
if (increment) {
|
||||
|
@ -819,7 +836,7 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
}
|
||||
|
||||
// if we carry to a new bit, change the scale
|
||||
if (unscaled.bitLength() > fracbits + 1) {
|
||||
if (unscaled.bitLength() > fracbits) {
|
||||
upscale(-1);
|
||||
}
|
||||
}
|
||||
|
@ -945,7 +962,7 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
* @return the truncated integer form of this BigFloat
|
||||
*/
|
||||
public BigInteger toBigInteger() {
|
||||
BigInteger res = unscaled.shiftRight(fracbits - scale);
|
||||
BigInteger res = unscaled.shiftRight(fracbits - scale - 1);
|
||||
if (sign < 0) {
|
||||
return res.negate();
|
||||
}
|
||||
|
@ -967,7 +984,7 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
*/
|
||||
public void round() {
|
||||
BigFloat half = new BigFloat(fracbits, expbits, FloatKind.FINITE, +1,
|
||||
BigInteger.ONE.shiftLeft(fracbits), -1);
|
||||
BigInteger.ONE.shiftLeft(fracbits - 1), -1);
|
||||
add(half);
|
||||
floor();
|
||||
}
|
||||
|
@ -1018,4 +1035,138 @@ public strictfp class BigFloat implements Comparable<BigFloat> {
|
|||
return this.sign * this.unscaled.compareTo(other.unscaled);
|
||||
}
|
||||
|
||||
private String formatSpecialCase() {
|
||||
if (isNaN()) {
|
||||
return NAN;
|
||||
}
|
||||
if (isInfinite()) {
|
||||
return sign < 0 ? NEGATIVE_INFINITY : POSITIVE_INFINITY;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform rounding and conversion to BigDecimal prior to generating
|
||||
* a formatted decimal string of the specified BigFloat value.
|
||||
* A default generated {@link MathContext} is used.
|
||||
* @return decimal string representation
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
String special = formatSpecialCase();
|
||||
if (special != null) {
|
||||
return special;
|
||||
}
|
||||
BigDecimal bd = toBigDecimal();
|
||||
bd = bd.round(getDefaultDisplayContext(fracbits));
|
||||
return bd.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform rounding and conversion to BigDecimal prior to generating
|
||||
* a formatted decimal string of the specified BigFloat value.
|
||||
* @param displayContext display context used for rounding and precision.
|
||||
* @return decimal string representation
|
||||
*/
|
||||
public String toString(MathContext displayContext) {
|
||||
String special = formatSpecialCase();
|
||||
if (special != null) {
|
||||
return special;
|
||||
}
|
||||
BigDecimal bd = toBigDecimal();
|
||||
bd = bd.round(displayContext);
|
||||
return bd.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform appropriate rounding and conversion to BigDecimal prior to generating
|
||||
* a formatted decimal string of the specified BigFloat value.
|
||||
* See {@link #toString(FloatFormat, boolean)},
|
||||
* {@link FloatFormat#toDecimalString(BigFloat)} and
|
||||
* {@link FloatFormat#toDecimalString(BigFloat, boolean)}.
|
||||
* @param ff float format
|
||||
* @param compact if true the precision will be reduced to a form which is still equivalent at
|
||||
* the binary encoding level for the specified FloatFormat.
|
||||
* @return decimal string representation
|
||||
*/
|
||||
public String toString(FloatFormat ff, boolean compact) {
|
||||
String special = formatSpecialCase();
|
||||
if (special != null) {
|
||||
return special;
|
||||
}
|
||||
BigDecimal bd = toBigDecimal();
|
||||
bd = bd.round(ff.getDisplayContext());
|
||||
|
||||
String str = bd.toString();
|
||||
int precision = bd.precision();
|
||||
int bdScale = bd.scale();
|
||||
|
||||
// Generate compact representation if requested
|
||||
if (compact && precision > 2) {
|
||||
BigInteger encoding = ff.getEncoding(this);
|
||||
for (String newStr = str; newStr != null;) {
|
||||
newStr = removeFractionalDigit(newStr, 1, false);
|
||||
if (newStr != null) {
|
||||
bd = new BigDecimal(newStr);
|
||||
bd = bd.setScale(bdScale); // avoid scale change which may alter encoding
|
||||
BigFloat bf = ff.getBigFloat(bd);
|
||||
if (encoding.equals(ff.getEncoding(bf))) {
|
||||
str = newStr;
|
||||
}
|
||||
else {
|
||||
newStr = null; // stop compaction
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Strip trailing zeros
|
||||
str = stripTrailingZeros(str, 1);
|
||||
// Ensure decimal point is present
|
||||
if (str.indexOf('.') < 0) {
|
||||
str += ".0";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
private String stripTrailingZeros(String decStr, int minDigits) {
|
||||
String str = decStr;
|
||||
while (true) {
|
||||
String nextStr = removeFractionalDigit(str, 1, true);
|
||||
if (nextStr == null) {
|
||||
break;
|
||||
}
|
||||
str = nextStr;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
private String removeFractionalDigit(String decStr, int minDigits, boolean stripZeroDigitOnly) {
|
||||
int decimalPointIx = decStr.indexOf('.');
|
||||
if (decimalPointIx < 0) {
|
||||
return null;
|
||||
}
|
||||
int expIx = decStr.toUpperCase().indexOf('E');
|
||||
String exp = "";
|
||||
if (expIx > 0) {
|
||||
exp = decStr.substring(expIx);
|
||||
decStr = decStr.substring(0, expIx);
|
||||
}
|
||||
if (decStr.length() - decimalPointIx - 1 <= minDigits) {
|
||||
return null;
|
||||
}
|
||||
int lastDigitIndex = decStr.length() - 1;
|
||||
if (stripZeroDigitOnly && decStr.charAt(lastDigitIndex) != '0') {
|
||||
return null;
|
||||
}
|
||||
// discard last mantissa digit
|
||||
return decStr.substring(0, lastDigitIndex) + exp;
|
||||
}
|
||||
|
||||
private static synchronized MathContext getDefaultDisplayContext(int fracBits) {
|
||||
return defaultDisplayContextMap.computeIfAbsent(fracBits, n -> {
|
||||
int precision = (int) (0.30103 * fracBits); // log10(2) * mantissa bits
|
||||
return new MathContext(precision, RoundingMode.HALF_EVEN);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -30,6 +29,7 @@ public class FloatFormatFactory {
|
|||
* Get float format
|
||||
* @param size format storage size in bytes
|
||||
* @return float format or null if size is not supported
|
||||
* @throws UnsupportedFloatFormatException if specified size is unsupported
|
||||
*/
|
||||
public static synchronized FloatFormat getFloatFormat(int size)
|
||||
throws UnsupportedFloatFormatException {
|
||||
|
@ -40,7 +40,6 @@ public class FloatFormatFactory {
|
|||
cache.put(size, format);
|
||||
}
|
||||
return format;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -129,7 +129,8 @@ class DataDB extends CodeUnitDB implements Data {
|
|||
}
|
||||
|
||||
private void computeLength() {
|
||||
length = dataType.getLength();
|
||||
// NOTE: Data intentionally does not use aligned-length
|
||||
length = dataType.getLength();
|
||||
|
||||
// undefined will never change their size
|
||||
if (dataType instanceof Undefined) {
|
||||
|
|
|
@ -36,6 +36,7 @@ class ArrayDB extends DataTypeDB implements Array {
|
|||
|
||||
private volatile String displayName;
|
||||
private ArrayDBAdapter adapter;
|
||||
private int elementLength; // lazy initialization
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -52,6 +53,7 @@ class ArrayDB extends DataTypeDB implements Array {
|
|||
|
||||
@Override
|
||||
protected String doGetName() {
|
||||
elementLength = -1; // signal refresh by getElementLength()
|
||||
return DataTypeUtilities.getName(this, true);
|
||||
}
|
||||
|
||||
|
@ -74,6 +76,7 @@ class ArrayDB extends DataTypeDB implements Array {
|
|||
@Override
|
||||
protected boolean refresh() {
|
||||
try {
|
||||
elementLength = -1;
|
||||
DBRecord rec = adapter.getRecord(key);
|
||||
if (rec != null) {
|
||||
record = rec;
|
||||
|
@ -129,6 +132,11 @@ class ArrayDB extends DataTypeDB implements Array {
|
|||
return getNumElements() * getElementLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlignedLength() {
|
||||
return getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
checkIsValid();
|
||||
|
@ -169,15 +177,23 @@ class ArrayDB extends DataTypeDB implements Array {
|
|||
|
||||
@Override
|
||||
public int getElementLength() {
|
||||
DataType dt = getDataType();
|
||||
int elementLen;
|
||||
if (dt instanceof Dynamic) {
|
||||
elementLen = record.getIntValue(ArrayDBAdapter.ARRAY_ELEMENT_LENGTH_COL);
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
DataType dt = getDataType();
|
||||
if (elementLength < 0) {
|
||||
if (dt instanceof Dynamic) {
|
||||
elementLength = record.getIntValue(ArrayDBAdapter.ARRAY_ELEMENT_LENGTH_COL);
|
||||
}
|
||||
else {
|
||||
elementLength = dt.getAlignedLength();
|
||||
}
|
||||
}
|
||||
return elementLength;
|
||||
}
|
||||
else {
|
||||
elementLen = dt.getLength();
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
return elementLen;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -251,7 +267,7 @@ class ArrayDB extends DataTypeDB implements Array {
|
|||
if (newDt instanceof Dynamic || newDt instanceof FactoryDataType) {
|
||||
newDt = DataType.DEFAULT;
|
||||
}
|
||||
int elementLength = newDt.getLength() < 0 ? oldElementLength : -1;
|
||||
elementLength = newDt.getLength() < 0 ? oldElementLength : -1;
|
||||
record.setIntValue(ArrayDBAdapter.ARRAY_ELEMENT_LENGTH_COL, elementLength);
|
||||
try {
|
||||
adapter.updateRecord(record);
|
||||
|
@ -288,7 +304,8 @@ class ArrayDB extends DataTypeDB implements Array {
|
|||
public void dataTypeSizeChanged(DataType dt) {
|
||||
lock.acquire();
|
||||
try {
|
||||
if (checkIsValid() && dt == getDataType()) {
|
||||
if (checkIsValid() && dt == getDataType() && dt.getLength() > 0) {
|
||||
elementLength = -1;
|
||||
notifySizeChanged(true);
|
||||
}
|
||||
}
|
||||
|
@ -333,6 +350,7 @@ class ArrayDB extends DataTypeDB implements Array {
|
|||
@Override
|
||||
public void dataTypeDeleted(DataType dt) {
|
||||
if (getDataType() == dt) {
|
||||
elementLength = -1;
|
||||
dataMgr.addDataTypeToDelete(key);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,6 +59,11 @@ abstract class CompositeDB extends DataTypeDB implements CompositeInternal {
|
|||
*/
|
||||
protected abstract void initialize();
|
||||
|
||||
@Override
|
||||
public final int getAlignedLength() {
|
||||
return getLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the preferred length for a new component. For Unions and packed
|
||||
* structures the preferred component length for a fixed-length dataType
|
||||
|
@ -78,18 +83,7 @@ abstract class CompositeDB extends DataTypeDB implements CompositeInternal {
|
|||
if ((isPackingEnabled() || (this instanceof Union)) && !(dataType instanceof Dynamic)) {
|
||||
length = -1; // force use of datatype size
|
||||
}
|
||||
int dtLength = dataType.getLength();
|
||||
if (length <= 0) {
|
||||
length = dtLength;
|
||||
}
|
||||
else if (dtLength > 0 && dtLength < length) {
|
||||
length = dtLength;
|
||||
}
|
||||
if (length <= 0) {
|
||||
throw new IllegalArgumentException("Positive length must be specified for " +
|
||||
dataType.getDisplayName() + " component");
|
||||
}
|
||||
return length;
|
||||
return DataTypeComponentImpl.getPreferredComponentLength(dataType, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -23,6 +23,7 @@ import ghidra.app.util.SymbolPathParser;
|
|||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
import ghidra.program.model.data.floats.AbstractFloatDataType;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
import ghidra.util.UniversalID;
|
||||
|
|
|
@ -453,6 +453,11 @@ class EnumDB extends DataTypeDB implements Enum {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlignedLength() {
|
||||
return getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
lock.acquire();
|
||||
|
|
|
@ -254,6 +254,11 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
|
|||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlignedLength() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Function Signature Data Type";
|
||||
|
|
|
@ -207,6 +207,12 @@ class PointerDB extends DataTypeDB implements Pointer {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlignedLength() {
|
||||
// assume pointers are never padded
|
||||
return getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
lock.acquire();
|
||||
|
|
|
@ -1709,7 +1709,7 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
|||
DataTypeComponent dtc = otherComponents[i];
|
||||
|
||||
DataType dt = resolvedDts[i]; // ancestry check already performed by caller
|
||||
int length = DataTypeComponent.usesZeroLengthComponent(dt) ? 0 : dt.getLength();
|
||||
int length = DataTypeComponent.usesZeroLengthComponent(dt) ? 0 : dt.getAlignedLength();
|
||||
if (length < 0 || dtc.isBitFieldComponent()) {
|
||||
// TODO: bitfield truncation/expansion may be an issue if data organization changes
|
||||
length = dtc.getLength();
|
||||
|
@ -1817,7 +1817,8 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
|||
if (dtc.getDataType() == dt) {
|
||||
// assume no impact to bitfields since base types should not change size
|
||||
int dtcLen = dtc.getLength();
|
||||
int length = DataTypeComponent.usesZeroLengthComponent(dt) ? 0 : dt.getLength();
|
||||
int length =
|
||||
DataTypeComponent.usesZeroLengthComponent(dt) ? 0 : dt.getAlignedLength();
|
||||
if (length < 0) {
|
||||
length = dtcLen;
|
||||
}
|
||||
|
@ -1875,7 +1876,7 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
|||
forceRepack |= isPacked;
|
||||
continue;
|
||||
}
|
||||
int length = DataTypeComponent.usesZeroLengthComponent(dt) ? 0 : dt.getLength();
|
||||
int length = DataTypeComponent.usesZeroLengthComponent(dt) ? 0 : dt.getAlignedLength();
|
||||
if (length < 0) {
|
||||
continue; // illegal condition - skip
|
||||
}
|
||||
|
@ -2304,7 +2305,7 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
|||
int nextIndex) throws IOException {
|
||||
|
||||
int oldLen = comp.getLength();
|
||||
int len = DataTypeComponent.usesZeroLengthComponent(newDt) ? 0 : newDt.getLength();
|
||||
int len = DataTypeComponent.usesZeroLengthComponent(newDt) ? 0 : newDt.getAlignedLength();
|
||||
if (len < 0) {
|
||||
len = oldLen;
|
||||
}
|
||||
|
|
|
@ -154,6 +154,11 @@ class TypedefDB extends DataTypeDB implements TypeDef {
|
|||
return getDataType().getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlignedLength() {
|
||||
return getDataType().getAlignedLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return getDataType().getDescription();
|
||||
|
|
|
@ -487,7 +487,7 @@ class UnionDB extends CompositeDB implements UnionInternal {
|
|||
if (dt instanceof BitFieldDataType) {
|
||||
dt = adjustBitField(dt); // in case base type changed
|
||||
}
|
||||
int length = DataTypeComponent.usesZeroLengthComponent(dt) ? 0 : dt.getLength();
|
||||
int length = DataTypeComponent.usesZeroLengthComponent(dt) ? 0 : dt.getAlignedLength();
|
||||
if (length < 0) {
|
||||
continue; // illegal condition - skip
|
||||
}
|
||||
|
@ -533,7 +533,8 @@ class UnionDB extends CompositeDB implements UnionInternal {
|
|||
boolean changed = false;
|
||||
for (DataTypeComponentDB dtc : components) {
|
||||
if (dtc.getDataType() == dt) {
|
||||
int length = DataTypeComponent.usesZeroLengthComponent(dt) ? 0 : dt.getLength();
|
||||
int length =
|
||||
DataTypeComponent.usesZeroLengthComponent(dt) ? 0 : dt.getAlignedLength();
|
||||
if (length >= 0 && length != dtc.getLength()) {
|
||||
dtc.setLength(length, true);
|
||||
changed = true;
|
||||
|
@ -824,7 +825,7 @@ class UnionDB extends CompositeDB implements UnionInternal {
|
|||
}
|
||||
else {
|
||||
int len = DataTypeComponent.usesZeroLengthComponent(newDt) ? 0
|
||||
: newDt.getLength();
|
||||
: newDt.getAlignedLength();
|
||||
if (len < 0) {
|
||||
len = dtc.getLength();
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.math.BigDecimal;
|
|||
|
||||
import generic.complex.Complex;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.program.model.data.floats.AbstractFloatDataType;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.program.model.mem.WrappedMemBuffer;
|
||||
|
||||
|
@ -86,9 +87,15 @@ public abstract class AbstractComplexDataType extends BuiltIn {
|
|||
return floatType.getLength() * 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlignedLength() {
|
||||
return getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "The data type for a complex number: a + bi";
|
||||
return "The data type for a complex number: a + bi; consisting of two " +
|
||||
floatType.getName() + " values";
|
||||
}
|
||||
|
||||
private static double toDouble(Object obj) {
|
||||
|
|
|
@ -78,6 +78,25 @@ public abstract class AbstractDataType implements DataType {
|
|||
: DataOrganizationImpl.getDefaultOrganization();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link DataOrganization} which should be used by a {@link AbstractDataType} when
|
||||
* associated with a specified {@link DataTypeManager dataMgr}. If a null
|
||||
* {@code dataMgr} is specified the default {@link DataOrganization} will be returned.
|
||||
* @param dataMgr datatype manager
|
||||
* @return the {@link DataOrganization} which should be used by a {@link AbstractDataType}
|
||||
* instance.
|
||||
*/
|
||||
protected static DataOrganization getDataOrganization(DataTypeManager dataMgr) {
|
||||
DataOrganization dataOrganization = null;
|
||||
if (dataMgr != null) {
|
||||
dataOrganization = dataMgr.getDataOrganization();
|
||||
}
|
||||
if (dataOrganization == null) {
|
||||
dataOrganization = DataOrganizationImpl.getDefaultOrganization();
|
||||
}
|
||||
return dataOrganization;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypePath getDataTypePath() {
|
||||
// use methods instead of fields since they mey be overriden
|
||||
|
|
|
@ -150,6 +150,11 @@ public abstract class AbstractPointerTypedefBuiltIn extends BuiltIn implements T
|
|||
return modelTypedef.getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlignedLength() {
|
||||
return modelTypedef.getAlignedLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getDataType() {
|
||||
return modelTypedef.getDataType();
|
||||
|
|
|
@ -299,7 +299,7 @@ class AlignedComponentPacker {
|
|||
int minOffset) {
|
||||
DataType componentDt = dataTypeComponent.getDataType();
|
||||
|
||||
int dtSize = componentDt.isZeroLength() ? 0 : componentDt.getLength();
|
||||
int dtSize = componentDt.isZeroLength() ? 0 : componentDt.getAlignedLength();
|
||||
if (dtSize < 0) {
|
||||
dtSize = dataTypeComponent.getLength();
|
||||
}
|
||||
|
|
|
@ -56,6 +56,10 @@ public class ArrayDataType extends DataTypeImpl implements Array {
|
|||
public ArrayDataType(DataType dataType, int numElements, int elementLength,
|
||||
DataTypeManager dtm) {
|
||||
super(dataType.getCategoryPath(), "array", dtm);
|
||||
if (dataType instanceof FactoryDataType) {
|
||||
throw new IllegalArgumentException(
|
||||
"Factory data type not permitted");
|
||||
}
|
||||
if (numElements < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Number of array elements may not be negative [" + numElements + "]");
|
||||
|
@ -75,6 +79,9 @@ public class ArrayDataType extends DataTypeImpl implements Array {
|
|||
}
|
||||
this.elementLength = elementLength;
|
||||
}
|
||||
else {
|
||||
this.elementLength = dataType.getAlignedLength();
|
||||
}
|
||||
this.dataType = dataType;
|
||||
this.numElements = numElements;
|
||||
name = DataTypeUtilities.getName(this, true);
|
||||
|
@ -168,6 +175,11 @@ public class ArrayDataType extends DataTypeImpl implements Array {
|
|||
return numElements * getElementLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlignedLength() {
|
||||
return getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Array of " + dataType.getDisplayName();
|
||||
|
@ -193,7 +205,8 @@ public class ArrayDataType extends DataTypeImpl implements Array {
|
|||
|
||||
@Override
|
||||
public void dataTypeSizeChanged(DataType dt) {
|
||||
if (dt == dataType) {
|
||||
if (dt == dataType && dt.getLength() > 0) {
|
||||
elementLength = dataType.getAlignedLength();
|
||||
notifySizeChanged();
|
||||
}
|
||||
}
|
||||
|
@ -217,7 +230,7 @@ public class ArrayDataType extends DataTypeImpl implements Array {
|
|||
|
||||
@Override
|
||||
public int getElementLength() {
|
||||
return (dataType instanceof Dynamic) ? elementLength : dataType.getLength();
|
||||
return elementLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -246,7 +259,9 @@ public class ArrayDataType extends DataTypeImpl implements Array {
|
|||
dataType.removeParent(this);
|
||||
dataType = newDt;
|
||||
dataType.addParent(this);
|
||||
elementLength = newDt.getLength() < 0 ? oldElementLength : -1;
|
||||
if (dataType.getLength() >= 0) {
|
||||
elementLength = dataType.getAlignedLength();
|
||||
}
|
||||
if (!getName().equals(oldName)) {
|
||||
notifyNameChanged(oldName);
|
||||
}
|
||||
|
|
|
@ -15,9 +15,8 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.docking.settings.*;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
|
@ -336,6 +335,11 @@ public class BitFieldDataType extends AbstractDataType {
|
|||
return storageSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlignedLength() {
|
||||
return getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
StringBuffer sbuf = new StringBuffer();
|
||||
|
|
|
@ -15,8 +15,10 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import ghidra.program.model.data.floats.Float64DataType;
|
||||
|
||||
/**
|
||||
* Provides a definition of a {@code complex} built-in data type consisting of two 8 byte floating point
|
||||
* Provides a definition of a {@code complex} built-in data type consisting of two 64-bit floating point
|
||||
* numbers in the IEEE 754 double precision format.
|
||||
*/
|
||||
public class Complex16DataType extends AbstractComplexDataType {
|
||||
|
@ -28,7 +30,7 @@ public class Complex16DataType extends AbstractComplexDataType {
|
|||
}
|
||||
|
||||
public Complex16DataType(DataTypeManager dtm) {
|
||||
super("complex16", Float8DataType.dataType, dtm);
|
||||
super("complex16", Float64DataType.dataType, dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -15,8 +15,10 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import ghidra.program.model.data.floats.Float128DataType;
|
||||
|
||||
/**
|
||||
* Provides a definition of a {@code complex} built-in data type consisting of two 16 byte floating point
|
||||
* Provides a definition of a {@code complex} built-in data type consisting of two 128-bit floating point
|
||||
* numbers in the IEEE 754 double precision format.
|
||||
*/
|
||||
public class Complex32DataType extends AbstractComplexDataType {
|
||||
|
@ -28,7 +30,7 @@ public class Complex32DataType extends AbstractComplexDataType {
|
|||
}
|
||||
|
||||
public Complex32DataType(DataTypeManager dtm) {
|
||||
super("complex32", Float16DataType.dataType, dtm);
|
||||
super("complex32", Float128DataType.dataType, dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -15,8 +15,10 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import ghidra.program.model.data.floats.Float32DataType;
|
||||
|
||||
/**
|
||||
* Provides a definition of a {@code complex} built-in data type consisting of two 4 byte floating point
|
||||
* Provides a definition of a {@code complex} built-in data type consisting of two 32-bit floating point
|
||||
* numbers in the IEEE 754 double precision format.
|
||||
*/
|
||||
|
||||
|
@ -29,7 +31,7 @@ public class Complex8DataType extends AbstractComplexDataType {
|
|||
}
|
||||
|
||||
public Complex8DataType(DataTypeManager dtm) {
|
||||
super("complex8", Float4DataType.dataType, dtm);
|
||||
super("complex8", Float32DataType.dataType, dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -62,6 +62,11 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
|
|||
description = "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getAlignedLength() {
|
||||
return getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStoredPackingValue() {
|
||||
return packing;
|
||||
|
@ -96,18 +101,7 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
|
|||
if ((isPackingEnabled() || (this instanceof Union)) && !(dataType instanceof Dynamic)) {
|
||||
length = -1; // force use of datatype size
|
||||
}
|
||||
int dtLength = dataType.getLength();
|
||||
if (length <= 0) {
|
||||
length = dtLength;
|
||||
}
|
||||
else if (dtLength > 0 && dtLength < length) {
|
||||
length = dtLength;
|
||||
}
|
||||
if (length <= 0) {
|
||||
throw new IllegalArgumentException("Positive length must be specified for " +
|
||||
dataType.getDisplayName() + " component");
|
||||
}
|
||||
return length;
|
||||
return DataTypeComponentImpl.getPreferredComponentLength(dataType, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -79,7 +79,7 @@ public abstract class CountedDynamicDataType extends DynamicDataType {
|
|||
int n = (int) getCount(memory, start.add(counterOffset));
|
||||
|
||||
DataTypeComponent[] comps = new DataTypeComponent[n + 1];
|
||||
DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(header, buf);
|
||||
DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(header, buf, false);
|
||||
|
||||
if (dti == null) {
|
||||
Msg.error(this, "ERROR: problem with data at " + buf.getAddress());
|
||||
|
@ -94,7 +94,7 @@ public abstract class CountedDynamicDataType extends DynamicDataType {
|
|||
try {
|
||||
newBuf.advance(countSize);
|
||||
for (int i = 1; i <= n; i++) {
|
||||
dti = DataTypeInstance.getDataTypeInstance(baseStruct, buf);
|
||||
dti = DataTypeInstance.getDataTypeInstance(baseStruct, buf, false);
|
||||
if (dti == null) {
|
||||
Msg.error(this, "ERROR: problem with data at " + buf.getAddress());
|
||||
return null;
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import ghidra.util.exception.NoValueException;
|
||||
import java.util.Arrays;
|
||||
|
||||
public interface DataOrganization {
|
||||
|
||||
|
@ -75,17 +75,17 @@ public interface DataOrganization {
|
|||
int getLongLongSize();
|
||||
|
||||
/**
|
||||
* @return the size of a float primitive data type in bytes.
|
||||
* @return the encoding size of a float primitive data type in bytes.
|
||||
*/
|
||||
int getFloatSize();
|
||||
|
||||
/**
|
||||
* @return the size of a double primitive data type in bytes.
|
||||
* @return the encoding size of a double primitive data type in bytes.
|
||||
*/
|
||||
int getDoubleSize();
|
||||
|
||||
/**
|
||||
* @return the size of a long double primitive data type in bytes.
|
||||
* @return the encoding size of a long double primitive data type in bytes.
|
||||
*/
|
||||
int getLongDoubleSize();
|
||||
|
||||
|
@ -119,12 +119,14 @@ public interface DataOrganization {
|
|||
int getDefaultPointerAlignment();
|
||||
|
||||
/**
|
||||
* Gets the alignment that is defined for a data type of the indicated size if one is defined.
|
||||
* @param size the size of the data type
|
||||
* Gets the primitive data alignment that is defined for the specified size. If no entry has
|
||||
* been defined for the specified size alignment of the next smaller map entry will be returned.
|
||||
* If the map is empty the {@link #getDefaultAlignment() default alignment}. The returned
|
||||
* value will not exceed the {@link #getAbsoluteMaxAlignment() defined maximum alignment}.
|
||||
* @param size the primitive data size
|
||||
* @return the alignment of the data type.
|
||||
* @throws NoValueException if there isn't an alignment defined for the indicated size.
|
||||
*/
|
||||
int getSizeAlignment(int size) throws NoValueException;
|
||||
int getSizeAlignment(int size);
|
||||
|
||||
/**
|
||||
* Get the composite bitfield packing information associated with this data organization.
|
||||
|
@ -139,8 +141,8 @@ public interface DataOrganization {
|
|||
int getSizeAlignmentCount();
|
||||
|
||||
/**
|
||||
* Gets the sizes that have an alignment specified.
|
||||
* @return the sizes with alignments mapped to them.
|
||||
* Gets the ordered list of sizes that have an alignment specified.
|
||||
* @return the ordered list of sizes with alignments mapped to them.
|
||||
*/
|
||||
int[] getSizes();
|
||||
|
||||
|
@ -213,19 +215,14 @@ public interface DataOrganization {
|
|||
}
|
||||
int[] keys = getSizes();
|
||||
int[] op2keys = obj.getSizes();
|
||||
if (keys.length != op2keys.length) {
|
||||
if (!Arrays.equals(keys, op2keys)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
for (int k : keys) {
|
||||
if (getSizeAlignment(k) != obj.getSizeAlignment(k)) {
|
||||
return false;
|
||||
}
|
||||
for (int k : keys) {
|
||||
if (getSizeAlignment(k) != obj.getSizeAlignment(k)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (NoValueException ex) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,11 +20,11 @@ import static ghidra.program.model.pcode.ElementId.*;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import ghidra.program.database.DBStringMapAdapter;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.model.pcode.Encoder;
|
||||
import ghidra.util.exception.NoValueException;
|
||||
import ghidra.util.xml.SpecXmlUtils;
|
||||
import ghidra.xml.XmlElement;
|
||||
import ghidra.xml.XmlPullParser;
|
||||
|
@ -48,9 +48,9 @@ public class DataOrganizationImpl implements DataOrganization {
|
|||
public static final int DEFAULT_INT_SIZE = 4;
|
||||
public static final int DEFAULT_LONG_SIZE = 4;
|
||||
public static final int DEFAULT_LONG_LONG_SIZE = 8;
|
||||
public static final int DEFAULT_FLOAT_SIZE = 4;
|
||||
public static final int DEFAULT_DOUBLE_SIZE = 8;
|
||||
public static final int DEFAULT_LONG_DOUBLE_SIZE = 8;
|
||||
public static final int DEFAULT_FLOAT_SIZE = 4; // encoding size only
|
||||
public static final int DEFAULT_DOUBLE_SIZE = 8; // encoding size only
|
||||
public static final int DEFAULT_LONG_DOUBLE_SIZE = 8; // encoding size only
|
||||
|
||||
// DBStringMapAdapter save/restore keys
|
||||
private static final String BIG_ENDIAN_NAME = "big_endian";
|
||||
|
@ -83,7 +83,7 @@ public class DataOrganizationImpl implements DataOrganization {
|
|||
/*
|
||||
* Map for determining the alignment of a data type based upon its size.
|
||||
*/
|
||||
private final HashMap<Integer, Integer> sizeAlignmentMap = new HashMap<>();
|
||||
private final TreeMap<Integer, Integer> sizeAlignmentMap = new TreeMap<>();
|
||||
|
||||
/**
|
||||
* Creates a new default DataOrganization. This has a mapping which defines the alignment
|
||||
|
@ -294,7 +294,7 @@ public class DataOrganizationImpl implements DataOrganization {
|
|||
}
|
||||
|
||||
/**
|
||||
* Defines the size of a float primitive data type.
|
||||
* Defines the encoding size of a float primitive data type.
|
||||
* @param floatSize the size of a float.
|
||||
*/
|
||||
public void setFloatSize(int floatSize) {
|
||||
|
@ -305,7 +305,7 @@ public class DataOrganizationImpl implements DataOrganization {
|
|||
}
|
||||
|
||||
/**
|
||||
* Defines the size of a double primitive data type.
|
||||
* Defines the encoding size of a double primitive data type.
|
||||
* @param doubleSize the size of a double.
|
||||
*/
|
||||
public void setDoubleSize(int doubleSize) {
|
||||
|
@ -319,7 +319,7 @@ public class DataOrganizationImpl implements DataOrganization {
|
|||
}
|
||||
|
||||
/**
|
||||
* Defines the size of a long double primitive data type.
|
||||
* Defines the encoding size of a long double primitive data type.
|
||||
* @param longDoubleSize the size of a long double.
|
||||
*/
|
||||
public void setLongDoubleSize(int longDoubleSize) {
|
||||
|
@ -409,15 +409,14 @@ public class DataOrganizationImpl implements DataOrganization {
|
|||
this.defaultPointerAlignment = defaultPointerAlignment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the alignment that is defined for a data type of the indicated size if one is defined.
|
||||
* @param size the size of the data type
|
||||
* @return the alignment of the data type.
|
||||
* @throws NoValueException if there isn't an alignment defined for the indicated size.
|
||||
*/
|
||||
@Override
|
||||
public int getSizeAlignment(int size) throws NoValueException {
|
||||
return sizeAlignmentMap.get(size);
|
||||
public int getSizeAlignment(int size) {
|
||||
Entry<Integer, Integer> floorEntry = sizeAlignmentMap.floorEntry(size);
|
||||
int alignment = floorEntry != null ? floorEntry.getValue() : defaultAlignment;
|
||||
if (absoluteMaxAlignment != 0) {
|
||||
return Math.min(alignment, absoluteMaxAlignment);
|
||||
}
|
||||
return alignment;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -500,7 +499,7 @@ public class DataOrganizationImpl implements DataOrganization {
|
|||
|
||||
@Override
|
||||
public int getAlignment(DataType dataType) {
|
||||
int dtSize = dataType.getLength();
|
||||
int dtSize = dataType.getAlignedLength();
|
||||
if (dataType instanceof Dynamic || dataType instanceof FactoryDataType || dtSize <= 0) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -525,18 +524,15 @@ public class DataOrganizationImpl implements DataOrganization {
|
|||
BitFieldDataType bitfieldDt = (BitFieldDataType) dataType;
|
||||
return getAlignment(bitfieldDt.getBaseDataType());
|
||||
}
|
||||
// Otherwise get the alignment based on the size.
|
||||
if (sizeAlignmentMap.containsKey(dtSize)) {
|
||||
int sizeAlignment = sizeAlignmentMap.get(dtSize);
|
||||
return ((absoluteMaxAlignment == 0) || (sizeAlignment < absoluteMaxAlignment))
|
||||
? sizeAlignment
|
||||
: absoluteMaxAlignment;
|
||||
}
|
||||
if (dataType instanceof Pointer) {
|
||||
|
||||
// If pointer size not found in size alignment map use default pointer alignment
|
||||
// TODO: this should probably be re-evaluated for its neccessity
|
||||
if (!sizeAlignmentMap.containsKey(dtSize) && dataType instanceof Pointer) {
|
||||
return getDefaultPointerAlignment();
|
||||
}
|
||||
// Otherwise just assume the default alignment.
|
||||
return getDefaultAlignment();
|
||||
|
||||
// Otherwise get the alignment based on the size.
|
||||
return getSizeAlignment(dtSize);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -551,7 +547,7 @@ public class DataOrganizationImpl implements DataOrganization {
|
|||
if (alignment <= 0) {
|
||||
return minimumOffset;
|
||||
}
|
||||
if ((alignment & 1) == 0) {
|
||||
if (isPowerOfTwo(alignment)) {
|
||||
// handle alignment which is a power-of-2
|
||||
return alignment + ((minimumOffset - 1) & ~(alignment - 1));
|
||||
}
|
||||
|
@ -560,6 +556,10 @@ public class DataOrganizationImpl implements DataOrganization {
|
|||
return minimumOffset + adj;
|
||||
}
|
||||
|
||||
private static boolean isPowerOfTwo(int n) {
|
||||
return (n & (n - 1)) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the least (lowest) common multiple of two numbers.
|
||||
* @param value1 the first number
|
||||
|
@ -689,13 +689,8 @@ public class DataOrganizationImpl implements DataOrganization {
|
|||
}
|
||||
|
||||
for (int size : dataOrg.getSizes()) {
|
||||
try {
|
||||
String key = keyPrefix + ELEM_SIZE_ALIGNMENT_MAP.name() + "." + size;
|
||||
dataMap.put(key, Integer.toString(dataOrg.getSizeAlignment(size)));
|
||||
}
|
||||
catch (NoValueException e) {
|
||||
// skip entry
|
||||
}
|
||||
String key = keyPrefix + ELEM_SIZE_ALIGNMENT_MAP.name() + "." + size;
|
||||
dataMap.put(key, Integer.toString(dataOrg.getSizeAlignment(size)));
|
||||
}
|
||||
|
||||
BitFieldPackingImpl.save(dataOrg.getBitFieldPacking(), dataMap,
|
||||
|
|
|
@ -15,9 +15,8 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
|
@ -227,17 +226,48 @@ public interface DataType {
|
|||
public String getMnemonic(Settings settings);
|
||||
|
||||
/**
|
||||
* Get the length (number of 8-bit bytes) of this DataType.
|
||||
* Get the length of this DataType as a number of 8-bit bytes.
|
||||
* <p>
|
||||
* NOTE: No datatype should ever return 0, even if {@link #isZeroLength()}, and only
|
||||
* {@link Dynamic} datatypes should return -1. If {@link #isZeroLength()} is true a length of 1
|
||||
* should be returned. Where a zero-length datatype can be handled (e.g., {@link Composite}) the
|
||||
* For primitive datatypes this reflects the smallest varnode which can be used to
|
||||
* contain its value (i.e., raw data length).
|
||||
* <p>
|
||||
* Example: For x86 32-bit gcc an 80-bit {@code long double} {@link #getLength() raw data length}
|
||||
* of 10-bytes will fit within a floating point register while its {@link #getAlignedLength() aligned-length}
|
||||
* of 12-bytes is used by the gcc compiler for data/array/component allocations to maintain alignment
|
||||
* (i.e., {@code sizeof(long double)} ).
|
||||
* <p>
|
||||
* NOTE: Other than the {@link VoidDataType}, no datatype should ever return 0, even if
|
||||
* {@link #isZeroLength()}, and only {@link Dynamic}/{@link FactoryDataType} datatypes
|
||||
* should return -1. If {@link #isZeroLength()} is true a length of 1 should be returned.
|
||||
* Where a zero-length datatype can be handled (e.g., {@link Composite}) the
|
||||
* {@link #isZeroLength()} method should be used.
|
||||
*
|
||||
* @return the length of this DataType
|
||||
*/
|
||||
public int getLength();
|
||||
|
||||
/**
|
||||
* Get the aligned-length of this datatype as a number of 8-bit bytes.
|
||||
* <p>
|
||||
* For primitive datatypes this is equivalent to the C/C++ "sizeof" operation within source code and
|
||||
* should be used when determining {@link Array} element length or component sizing for a
|
||||
* {@link Composite}. For {@link Pointer}, {@link Composite} and {@link Array} types this will
|
||||
* return the same value as {@link #getLength()}.
|
||||
* <p>
|
||||
* Example: For x86 32-bit gcc an 80-bit {@code long double} {@link #getLength() raw data length}
|
||||
* of 10-bytes will fit within a floating point register while its {@link #getAlignedLength() aligned-length}
|
||||
* of 12-bytes is used by the gcc compiler for data/array/component allocations to maintain alignment
|
||||
* (i.e., {@code sizeof(long double)} ).
|
||||
* <p>
|
||||
* NOTE: Other than the {@link VoidDataType}, no datatype should ever return 0, even if
|
||||
* {@link #isZeroLength()}, and only {@link Dynamic} / {@link FactoryDataType} /
|
||||
* {@link FunctionDefinition} datatypes should return -1. If {@link #isZeroLength()} is true
|
||||
* a length of 1 should be returned.
|
||||
*
|
||||
* @return byte length of binary encoding.
|
||||
*/
|
||||
public int getAlignedLength();
|
||||
|
||||
/**
|
||||
* Indicates this datatype is defined with a zero length.
|
||||
* <p>
|
||||
|
|
|
@ -347,4 +347,32 @@ public class DataTypeComponentImpl implements InternalDataTypeComponent, Seriali
|
|||
return InternalDataTypeComponent.toString(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the preferred length for a new component. The length returned will be no
|
||||
* larger than the specified length.
|
||||
*
|
||||
* @param dataType new component datatype
|
||||
* @param length constrained length or -1 to force use of dataType size.
|
||||
* Dynamic types such as string must have a positive length
|
||||
* specified.
|
||||
* @return preferred component length
|
||||
*/
|
||||
public static int getPreferredComponentLength(DataType dataType, int length) {
|
||||
if (DataTypeComponent.usesZeroLengthComponent(dataType)) {
|
||||
return 0;
|
||||
}
|
||||
int dtLength = dataType.getAlignedLength();
|
||||
if (length <= 0) {
|
||||
length = dtLength;
|
||||
}
|
||||
else if (dtLength > 0 && dtLength < length) {
|
||||
length = dtLength;
|
||||
}
|
||||
if (length <= 0) {
|
||||
throw new IllegalArgumentException("Positive length must be specified for " +
|
||||
dataType.getDisplayName() + " component");
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -36,6 +36,8 @@ public abstract class DataTypeImpl extends AbstractDataType {
|
|||
// defaultSettings implementation established by its DataTypeManager.
|
||||
protected Settings defaultSettings;
|
||||
|
||||
private Integer alignedLength;
|
||||
|
||||
private List<WeakReference<DataType>> parentList;
|
||||
private UniversalID universalID;
|
||||
private SourceArchive sourceArchive;
|
||||
|
@ -91,6 +93,43 @@ public abstract class DataTypeImpl extends AbstractDataType {
|
|||
return getDataTypePath().getPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the aligned-length for a fixed length datatype. This is intended to produce a
|
||||
* result consistent with the C/C++ {@code sizeof(type)} operation. Use of this method
|
||||
* with {@link TypeDef} is not allowed.
|
||||
* Whereas {@link #getLength()} corresponds to the raw type size which may be moved into
|
||||
* a smaller register/varnode. Example: this frequently occurs with encoded floating-point
|
||||
* data such as a 10-byte/80-bit encoding which is stored in memory as 12 or 16-bytes in order
|
||||
* to maintain memory alignment constraints.
|
||||
* @param dataType datatype
|
||||
* @return aligned-length or -1 if not a fixed-length datatype
|
||||
*/
|
||||
private static int computeAlignedLength(DataType dataType) {
|
||||
if ((dataType instanceof TypeDef) || (dataType instanceof Composite) ||
|
||||
(dataType instanceof Array)) {
|
||||
// Typedefs must defer to base datatype for aligned-length determination
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
int len = dataType.getLength();
|
||||
if (len <= 0 || (dataType instanceof Pointer)) {
|
||||
return len;
|
||||
}
|
||||
int align = dataType.getDataOrganization().getSizeAlignment(len);
|
||||
int mod = len % align;
|
||||
if (mod != 0) {
|
||||
len += (align - mod);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlignedLength() {
|
||||
if (alignedLength == null) {
|
||||
alignedLength = computeAlignedLength(this);
|
||||
}
|
||||
return alignedLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlignment() {
|
||||
int length = getLength();
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,6 +15,7 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import ghidra.program.model.listing.Data;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
|
||||
/**
|
||||
|
@ -33,6 +33,9 @@ public class DataTypeInstance {
|
|||
|
||||
/**
|
||||
* Create an instance of a data type with the given length.
|
||||
* <br>
|
||||
* NOTE: fixed-length primitive datatypes assume {@link DataType#getLength() raw datatype length}
|
||||
* intended for {@link Data} use.
|
||||
*
|
||||
* @param dt data type
|
||||
* @param length fixed length of the data type
|
||||
|
@ -66,25 +69,44 @@ public class DataTypeInstance {
|
|||
this.length = length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return dataType.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a data-type instance
|
||||
* Factory and Dynamic data-types are NOT handled.
|
||||
* @param dataType
|
||||
* @param buf
|
||||
* @param dataType data type
|
||||
* @param buf memory buffer
|
||||
* @param useAlignedLength if true a fixed-length primitive data type will use its
|
||||
* {@link DataType#getAlignedLength() aligned-length}, otherwise it will use its
|
||||
* {@link DataType#getLength() raw length}. NOTE: This generally only relates to
|
||||
* float datatypes whose raw encoding length may be shorter than their aligned-length
|
||||
* generally corresponding to a compiler's "sizeof(type)" value. This should generally be
|
||||
* true for {@link DataTypeComponent} and false for simple {@link Data} instances.
|
||||
* @return data-type instance or null if one could not be determined
|
||||
*/
|
||||
public static DataTypeInstance getDataTypeInstance(DataType dataType, MemBuffer buf) {
|
||||
return getDataTypeInstance(dataType, buf, -1);
|
||||
public static DataTypeInstance getDataTypeInstance(DataType dataType, MemBuffer buf,
|
||||
boolean useAlignedLength) {
|
||||
return getDataTypeInstance(dataType, buf, -1, useAlignedLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to create a fixed-length data-type instance.
|
||||
* Factory and non-sizable Dynamic data-types are NOT handled.
|
||||
* @param dataType
|
||||
* @param dataType data type
|
||||
* @param length length for sizable Dynamic data-types, otherwise ignored
|
||||
* @param useAlignedLength if true a fixed-length primitive data type will use its
|
||||
* {@link DataType#getAlignedLength() aligned-length}, otherwise it will use its
|
||||
* {@link DataType#getLength() raw length}. NOTE: This generally only relates to
|
||||
* float datatypes whose raw encoding length may be shorter than their aligned-length
|
||||
* generally corresponding to a compiler's "sizeof(type)" value. This should generally be
|
||||
* true for {@link DataTypeComponent} and false for simple {@link Data} instances.
|
||||
* @return data-type instance or null if unable to create instance.
|
||||
*/
|
||||
public static DataTypeInstance getDataTypeInstance(DataType dataType, int length) {
|
||||
public static DataTypeInstance getDataTypeInstance(DataType dataType, int length,
|
||||
boolean useAlignedLength) {
|
||||
if (dataType == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -105,6 +127,9 @@ public class DataTypeInstance {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
else if (useAlignedLength) {
|
||||
length = dataType.getAlignedLength();
|
||||
}
|
||||
else {
|
||||
length = dataType.getLength();
|
||||
}
|
||||
|
@ -116,20 +141,26 @@ public class DataTypeInstance {
|
|||
return new DataTypeInstance(dataType, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return dataType.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to create a data-type instance associated with a specific memory location.
|
||||
* Factory and Dynamic data-types are handled.
|
||||
* <br>
|
||||
* NOTE: fixed-length primitive datatypes assume {@link DataType#getLength() raw datatype length}
|
||||
* intended for {@link Data} use.
|
||||
*
|
||||
* @param dataType
|
||||
* @param buf memory location
|
||||
* @param length length for sizable Dynamic data-types, otherwise ignored
|
||||
* @param useAlignedLength if true a fixed-length primitive data type will use its
|
||||
* {@link DataType#getAlignedLength() aligned-length}, otherwise it will use its
|
||||
* {@link DataType#getLength() raw length}. NOTE: This generally only relates to
|
||||
* float datatypes whose raw encoding length may be shorter than their aligned-length
|
||||
* generally corresponding to a compiler's "sizeof(type)" value. This should generally be
|
||||
* true for {@link DataTypeComponent} and false for simple {@link Data} instances.
|
||||
* @return data-type instance or null if unable to create instance.
|
||||
*/
|
||||
public static DataTypeInstance getDataTypeInstance(DataType dataType, MemBuffer buf, int length) {
|
||||
public static DataTypeInstance getDataTypeInstance(DataType dataType, MemBuffer buf, int length,
|
||||
boolean useAlignedLength) {
|
||||
if (dataType instanceof FactoryDataType) {
|
||||
dataType = ((FactoryDataType) dataType).getDataType(buf);
|
||||
length = -1; // ignore user-specified length for factory use
|
||||
|
@ -151,6 +182,9 @@ public class DataTypeInstance {
|
|||
Dynamic dynamicDataType = (Dynamic) dataType;
|
||||
length = dynamicDataType.getLength(buf, length);
|
||||
}
|
||||
else if (useAlignedLength) {
|
||||
length = dataType.getAlignedLength();
|
||||
}
|
||||
else {
|
||||
length = dataType.getLength();
|
||||
}
|
||||
|
|
|
@ -259,10 +259,10 @@ public final class DataUtilities {
|
|||
DataTypeInstance dti;
|
||||
if (length > 0 && (realType instanceof Dynamic) &&
|
||||
((Dynamic) realType).canSpecifyLength()) {
|
||||
dti = DataTypeInstance.getDataTypeInstance(newType, memBuf, length);
|
||||
dti = DataTypeInstance.getDataTypeInstance(newType, memBuf, length, false);
|
||||
}
|
||||
else {
|
||||
dti = DataTypeInstance.getDataTypeInstance(newType, memBuf);
|
||||
dti = DataTypeInstance.getDataTypeInstance(newType, memBuf, false);
|
||||
}
|
||||
|
||||
if (dti == null) {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import ghidra.program.model.data.floats.AbstractFloatDataType;
|
||||
|
||||
/**
|
||||
* Provides a definition of a Double within a program.
|
||||
|
@ -31,7 +32,12 @@ public class DoubleDataType extends AbstractFloatDataType {
|
|||
}
|
||||
|
||||
public DoubleDataType(DataTypeManager dtm) {
|
||||
super("double", dtm);
|
||||
super("double", getDataOrganization(dtm).getDoubleSize(), dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String buildDescription() {
|
||||
return "Compiler-defined 'double' " + super.buildDescription();
|
||||
}
|
||||
|
||||
public DataType clone(DataTypeManager dtm) {
|
||||
|
@ -46,9 +52,4 @@ public class DoubleDataType extends AbstractFloatDataType {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return getDataOrganization().getDoubleSize();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -239,6 +239,11 @@ public class EnumDataType extends GenericDataType implements Enum {
|
|||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlignedLength() {
|
||||
return getLength();
|
||||
}
|
||||
|
||||
public void setLength(int newLength) {
|
||||
if (newLength == length) {
|
||||
return;
|
||||
|
|
|
@ -137,7 +137,7 @@ public abstract class FactoryStructureDataType extends BuiltIn implements Factor
|
|||
|
||||
protected DataTypeComponent addComponent(Structure es, DataType dt, String componentName) {
|
||||
|
||||
return es.add(dt, dt.getLength(), componentName, null);
|
||||
return es.add(dt, dt.getAlignedLength(), componentName, null);
|
||||
}
|
||||
|
||||
protected abstract void populateDynamicStructure(MemBuffer buf, Structure es);
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
public class Float8DataType extends AbstractFloatDataType {
|
||||
|
||||
public static final Float8DataType dataType = new Float8DataType();
|
||||
|
||||
public Float8DataType() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public Float8DataType(DataTypeManager dtm) {
|
||||
super("float8", dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType clone(DataTypeManager dtm) {
|
||||
if (dtm == getDataTypeManager()) {
|
||||
return this;
|
||||
}
|
||||
return new Float8DataType(dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return 8;
|
||||
}
|
||||
|
||||
}
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import ghidra.program.model.data.floats.AbstractFloatDataType;
|
||||
|
||||
/**
|
||||
* Provides a definition of a Float within a program.
|
||||
*/
|
||||
|
@ -30,7 +32,12 @@ public class FloatDataType extends AbstractFloatDataType {
|
|||
}
|
||||
|
||||
public FloatDataType(DataTypeManager dtm) {
|
||||
super("float", dtm);
|
||||
super("float", getDataOrganization(dtm).getFloatSize(), dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String buildDescription() {
|
||||
return "Compiler-defined 'float' " + super.buildDescription();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -46,9 +53,4 @@ public class FloatDataType extends AbstractFloatDataType {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return getDataOrganization().getFloatSize();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -169,7 +169,7 @@ public abstract class IndexedDynamicDataType extends DynamicDataType {
|
|||
comps = new DataTypeComponent[2];
|
||||
}
|
||||
MemoryBufferImpl newBuf = new MemoryBufferImpl(memory, buf.getAddress());
|
||||
DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(header, newBuf);
|
||||
DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(header, newBuf, false);
|
||||
if (dti == null) {
|
||||
Msg.error(this, "ERROR: problem with data at " + newBuf.getAddress());
|
||||
return null;
|
||||
|
@ -183,7 +183,7 @@ public abstract class IndexedDynamicDataType extends DynamicDataType {
|
|||
int offset = countSize;
|
||||
newBuf = new MemoryBufferImpl(memory, buf.getAddress());
|
||||
newBuf.advance(countSize);
|
||||
dti = DataTypeInstance.getDataTypeInstance(data, newBuf);
|
||||
dti = DataTypeInstance.getDataTypeInstance(data, newBuf, false);
|
||||
if (dti == null) {
|
||||
Msg.error(this, "ERROR: problem with data at " + newBuf.getAddress());
|
||||
return null;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import ghidra.program.model.data.floats.AbstractFloatDataType;
|
||||
|
||||
/**
|
||||
* Provides a definition of a Long Double within a program.
|
||||
|
@ -31,7 +32,12 @@ public class LongDoubleDataType extends AbstractFloatDataType {
|
|||
}
|
||||
|
||||
public LongDoubleDataType(DataTypeManager dtm) {
|
||||
super("longdouble", dtm);
|
||||
super("longdouble", getDataOrganization(dtm).getLongDoubleSize(), dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String buildDescription() {
|
||||
return "Compiler-defined 'long double' " + super.buildDescription();
|
||||
}
|
||||
|
||||
public DataType clone(DataTypeManager dtm) {
|
||||
|
@ -50,9 +56,4 @@ public class LongDoubleDataType extends AbstractFloatDataType {
|
|||
public boolean hasLanguageDependantLength() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return getDataOrganization().getLongDoubleSize();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import ghidra.program.model.data.floats.AbstractFloatDataType;
|
||||
|
||||
public enum MetaDataType {
|
||||
// Enumerations are ordered in terms of how "specific" the data-type class is
|
||||
VOID, // "void" data-type
|
||||
|
|
|
@ -31,6 +31,9 @@ import ghidra.program.model.pcode.PartialUnion;
|
|||
* In a conflict, less specific data-types are replaced.
|
||||
* After all information is collected a final Structure can be built by iterating over
|
||||
* the final field entries.
|
||||
*
|
||||
* NOTE: No attempt has been made to utilize {@link DataType#getAlignedLength()} when considering
|
||||
* component type lengths.
|
||||
*/
|
||||
public class NoisyStructureBuilder {
|
||||
private TreeMap<Long, DataType> offsetToDataTypeMap = new TreeMap<>();
|
||||
|
|
|
@ -171,6 +171,11 @@ public class PointerDataType extends BuiltIn implements Pointer {
|
|||
return length <= 0 ? getDataOrganization().getPointerSize() : length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlignedLength() {
|
||||
return getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultLabelPrefix() {
|
||||
return POINTER_LABEL_PREFIX;
|
||||
|
|
|
@ -210,6 +210,11 @@ public class PointerTypedef extends GenericDataType implements TypeDef {
|
|||
return modelTypedef.getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlignedLength() {
|
||||
return modelTypedef.getAlignedLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getDataType() {
|
||||
return modelTypedef.getDataType();
|
||||
|
|
|
@ -60,7 +60,8 @@ public abstract class RepeatCountDataType extends DynamicDataType {
|
|||
MemoryBufferImpl newBuf = new MemoryBufferImpl(buf.getMemory(), buf.getAddress());
|
||||
newBuf.advance(countSize);
|
||||
for (int i = 1; i < n; i++) {
|
||||
DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(repeatDataType, newBuf);
|
||||
DataTypeInstance dti =
|
||||
DataTypeInstance.getDataTypeInstance(repeatDataType, newBuf, false);
|
||||
if (dti == null) {
|
||||
Msg.error(this, "ERROR: problem with data at " + newBuf.getAddress());
|
||||
return null;
|
||||
|
|
|
@ -96,7 +96,8 @@ public abstract class RepeatedDynamicDataType extends DynamicDataType {
|
|||
try {
|
||||
newBuf.advance(countSize);
|
||||
while (moreComponents(memory, newBuf.getAddress())) {
|
||||
DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(baseStruct, newBuf);
|
||||
DataTypeInstance dti =
|
||||
DataTypeInstance.getDataTypeInstance(baseStruct, newBuf, false);
|
||||
if (dti == null) {
|
||||
Msg.error(this, "ERROR: problem with data at " + newBuf.getAddress());
|
||||
return null;
|
||||
|
|
|
@ -102,7 +102,8 @@ public abstract class StructuredDynamicDataType extends DynamicDataType {
|
|||
MemoryBufferImpl newBuf = new MemoryBufferImpl(memory, buf.getAddress());
|
||||
try {
|
||||
for (int i = 0; i < components.size(); i++) {
|
||||
DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(components.get(i), newBuf);
|
||||
DataTypeInstance dti =
|
||||
DataTypeInstance.getDataTypeInstance(components.get(i), newBuf, false);
|
||||
if (dti == null) {
|
||||
Msg.error(this, "Invalid data at " + newBuf.getAddress());
|
||||
return null;
|
||||
|
|
|
@ -209,6 +209,11 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
|
|||
return dataType.getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlignedLength() {
|
||||
return dataType.getAlignedLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
|
||||
return dataType.getRepresentation(buf, settings, length);
|
||||
|
|
|
@ -13,9 +13,8 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.data;
|
||||
package ghidra.program.model.data.floats;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.TreeMap;
|
||||
|
||||
|
@ -23,6 +22,7 @@ import ghidra.docking.settings.Settings;
|
|||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.pcode.floatformat.*;
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
|
||||
/**
|
||||
|
@ -30,61 +30,99 @@ import ghidra.program.model.mem.MemBuffer;
|
|||
*/
|
||||
public abstract class AbstractFloatDataType extends BuiltIn {
|
||||
|
||||
private final static long serialVersionUID = 1;
|
||||
|
||||
// TODO: Add FloatDisplayPrecisionSettingsDefinition
|
||||
private static SettingsDefinition[] SETTINGS_DEFS = {};
|
||||
|
||||
public AbstractFloatDataType(String name, DataTypeManager dtm) {
|
||||
super(null, name, dtm);
|
||||
}
|
||||
private final FloatFormat floatFormat;
|
||||
private final int encodedLength;
|
||||
|
||||
private String description;
|
||||
|
||||
/**
|
||||
*
|
||||
* @see ghidra.program.model.data.DataType#getMnemonic(Settings)
|
||||
* Abstract float datatype constructor
|
||||
* @param name name of the float datatype.
|
||||
* @param encodedLength the floating encoding length as number of 8-bit bytes.
|
||||
* @param dtm associated datatype manager which dictates the {@link DataOrganization} to
|
||||
* be used. This argument may be null to adopt the default data organization.
|
||||
*/
|
||||
public AbstractFloatDataType(String name, int encodedLength, DataTypeManager dtm) {
|
||||
super(null, name, dtm);
|
||||
if (encodedLength < 1) {
|
||||
throw new IllegalArgumentException("Invalid encoded length: " + encodedLength);
|
||||
}
|
||||
this.encodedLength = encodedLength;
|
||||
FloatFormat format = null;
|
||||
try {
|
||||
// Establish float format
|
||||
format = FloatFormatFactory.getFloatFormat(getLength());
|
||||
}
|
||||
catch (UnsupportedFloatFormatException e) {
|
||||
// ignore
|
||||
}
|
||||
floatFormat = format;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMnemonic(Settings settings) {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see ghidra.program.model.data.DataType#getDescription()
|
||||
*/
|
||||
protected final String buildIEEE754StandardDescription() {
|
||||
StringBuilder buf = new StringBuilder("IEEE 754 floating-point type (");
|
||||
int bitLen = encodedLength * 8;
|
||||
buf.append(Integer.toString(bitLen));
|
||||
buf.append("-bit / ");
|
||||
buf.append(Integer.toString(encodedLength));
|
||||
buf.append("-byte format, aligned-length is ");
|
||||
buf.append(Integer.toString(getAlignedLength()));
|
||||
buf.append("-bytes)");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
protected String buildDescription() {
|
||||
return buildIEEE754StandardDescription();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "IEEE-754 Float";
|
||||
public final String getDescription() {
|
||||
if (description == null) {
|
||||
description = buildDescription();
|
||||
}
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getValueClass(Settings settings) {
|
||||
return BigFloat.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the encoded length (number of 8-bit bytes) of this float datatype.
|
||||
*
|
||||
* @see ghidra.program.model.data.DataType#getValue(ghidra.program.model.mem.MemBuffer,
|
||||
* ghidra.docking.settings.Settings, int)
|
||||
* @return encoded length of this float datatype.
|
||||
*/
|
||||
@Override
|
||||
public Object getValue(MemBuffer buf, Settings settings, int length) {
|
||||
public final int getLength() {
|
||||
return encodedLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigFloat getValue(MemBuffer buf, Settings settings, int length) {
|
||||
try {
|
||||
int len = getLength(); // use type length (ignore length arg)
|
||||
FloatFormat floatFormat = FloatFormatFactory.getFloatFormat(len);
|
||||
if (floatFormat == null) {
|
||||
return null;
|
||||
}
|
||||
byte[] bytes = new byte[len];
|
||||
if (buf.getBytes(bytes, 0) != len) {
|
||||
return null;
|
||||
}
|
||||
if (len <= 8) {
|
||||
long value = Utils.bytesToLong(bytes, len, buf.isBigEndian());
|
||||
double doubleValue = floatFormat.getHostFloat(value);
|
||||
switch (len) {
|
||||
case 2:
|
||||
// TODO: GP-1379
|
||||
return (short) doubleValue;
|
||||
case 4:
|
||||
return (float) doubleValue;
|
||||
}
|
||||
return doubleValue;
|
||||
return floatFormat.decodeBigFloat(value);
|
||||
}
|
||||
BigInteger value = Utils.bytesToBigInteger(bytes, len, buf.isBigEndian(), false);
|
||||
BigDecimal decValue = floatFormat.round(floatFormat.getHostFloat(value));
|
||||
return decValue;
|
||||
return floatFormat.decodeBigFloat(value);
|
||||
}
|
||||
catch (UnsupportedFloatFormatException e) {
|
||||
return null;
|
||||
|
@ -93,31 +131,25 @@ public abstract class AbstractFloatDataType extends BuiltIn {
|
|||
|
||||
@Override
|
||||
public boolean isEncodable() {
|
||||
int length = getLength();
|
||||
return length == 4 || length == 8;
|
||||
return floatFormat != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encodeValue(Object value, MemBuffer buf, Settings settings, int length)
|
||||
throws DataTypeEncodeException {
|
||||
// value expected as Number or BigFloat object
|
||||
try {
|
||||
int len = getLength();
|
||||
if (length != -1 && length != len) {
|
||||
throw new DataTypeEncodeException("Length mismatch", value, this);
|
||||
if (floatFormat == null) {
|
||||
throw new DataTypeEncodeException(
|
||||
"Unsupported float format (" + len + " bytes)", value, this);
|
||||
}
|
||||
FloatFormat floatFormat = FloatFormatFactory.getFloatFormat(len);
|
||||
if (len == 8 || len == 4) {
|
||||
if (!(value instanceof Number)) {
|
||||
throw new DataTypeEncodeException(
|
||||
"length-" + len + " float requires Number type", value, this);
|
||||
}
|
||||
if ((len == 8 || len == 4) && (value instanceof Number)) {
|
||||
double doubleValue = ((Number) value).doubleValue();
|
||||
long encoding = floatFormat.getEncoding(doubleValue);
|
||||
return Utils.longToBytes(encoding, len, buf.isBigEndian());
|
||||
}
|
||||
if (!(value instanceof BigFloat)) {
|
||||
// TODO: BigFloat really ought to have a valueOf(double) method, or --
|
||||
// TODO: -- or BigFloat really ought to have a valueOf(BigDecimal) method
|
||||
throw new DataTypeEncodeException(
|
||||
"non-standard float length requires BigFloat type", value, this);
|
||||
}
|
||||
|
@ -132,17 +164,13 @@ public abstract class AbstractFloatDataType extends BuiltIn {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see ghidra.program.model.data.DataType#getRepresentation(MemBuffer, Settings, int)
|
||||
*/
|
||||
@Override
|
||||
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
|
||||
Object obj = getValue(buf, settings, length);
|
||||
if (obj == null) {
|
||||
BigFloat value = getValue(buf, settings, length);
|
||||
if (value == null) {
|
||||
return "??";
|
||||
}
|
||||
return obj.toString();
|
||||
return floatFormat != null ? floatFormat.toDecimalString(value, true) : value.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -150,16 +178,17 @@ public abstract class AbstractFloatDataType extends BuiltIn {
|
|||
throws DataTypeEncodeException {
|
||||
try {
|
||||
int len = getLength();
|
||||
if (length != -1 && length != len) {
|
||||
throw new DataTypeEncodeException("Length mismatch", repr, this);
|
||||
if (floatFormat == null) {
|
||||
throw new DataTypeEncodeException(
|
||||
"Unsupported float format (" + len + " bytes)", repr, this);
|
||||
}
|
||||
if (length == 8 || length == 4) {
|
||||
double doubleValue = Double.parseDouble(repr);
|
||||
return encodeValue(doubleValue, buf, settings, length);
|
||||
}
|
||||
// TODO: BigFloat ought to have a parse(String) method, or valueOf(BigDecimal)
|
||||
throw new DataTypeEncodeException(
|
||||
"Cannot yet parse values of non-standard float length", repr, this);
|
||||
BigFloat bf = floatFormat.getBigFloat(repr);
|
||||
floatFormat.round(bf);
|
||||
return encodeValue(bf, buf, settings, length);
|
||||
}
|
||||
catch (DataTypeEncodeException e) {
|
||||
throw e;
|
||||
|
@ -169,9 +198,6 @@ public abstract class AbstractFloatDataType extends BuiltIn {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.BuiltIn#getBuiltInSettingsDefinitions()
|
||||
*/
|
||||
@Override
|
||||
protected SettingsDefinition[] getBuiltInSettingsDefinitions() {
|
||||
return SETTINGS_DEFS;
|
||||
|
@ -184,6 +210,8 @@ public abstract class AbstractFloatDataType extends BuiltIn {
|
|||
|
||||
@Override
|
||||
public String getCTypeDeclaration(DataOrganization dataOrganization) {
|
||||
// NOTE: There are a variety of naming conventions for fixed-length floats
|
||||
// so we will just use our name and rely on user to edit to suit there needs.
|
||||
return hasLanguageDependantLength() ? null : name;
|
||||
}
|
||||
|
||||
|
@ -196,53 +224,60 @@ public abstract class AbstractFloatDataType extends BuiltIn {
|
|||
if (floatTypes == null) {
|
||||
// unsupported sizes filled-in with a null
|
||||
floatTypes = new TreeMap<Integer, AbstractFloatDataType>();
|
||||
floatTypes.put(2, Float2DataType.dataType);
|
||||
floatTypes.put(4, Float4DataType.dataType);
|
||||
floatTypes.put(8, Float8DataType.dataType);
|
||||
floatTypes.put(10, Float10DataType.dataType);
|
||||
floatTypes.put(16, Float16DataType.dataType);
|
||||
floatTypes.put(Float16DataType.dataType.getLength(), Float16DataType.dataType);
|
||||
floatTypes.put(Float32DataType.dataType.getLength(), Float32DataType.dataType);
|
||||
floatTypes.put(Float64DataType.dataType.getLength(), Float64DataType.dataType);
|
||||
floatTypes.put(Float80DataType.dataType.getLength(), Float80DataType.dataType);
|
||||
floatTypes.put(Float128DataType.dataType.getLength(), Float128DataType.dataType);
|
||||
}
|
||||
return floatTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Float data-type instance of the requested size
|
||||
* Get a Float data-type instance with the requested raw format size in bytes. It is important that the
|
||||
* "raw" format size is specified since the {@link DataType#getAlignedLength() aligned-length}
|
||||
* used by compilers (e.g., {@code sizeof()}) may be larger and duplicated across different
|
||||
* float formats. Example: an 80-bit (10-byte) float may have an aligned-length of 12 or 16-bytes
|
||||
* based upon alignment requirements of a given compiler. This can result in multiple float
|
||||
* types having the same aligned-length.
|
||||
*
|
||||
* @param size data type size, unsupported sizes will cause an undefined type to be returned.
|
||||
* @param rawFormatByteSize raw float format size, unsupported sizes will cause an undefined
|
||||
* type to be returned.
|
||||
* @param dtm optional program data-type manager, if specified a generic data-type will be
|
||||
* returned if possible (i.e., float, double, long double).
|
||||
* returned if possible (i.e., float, double, long double).
|
||||
* @return float data type of specified size
|
||||
*/
|
||||
public static DataType getFloatDataType(int size, DataTypeManager dtm) {
|
||||
if (size < 1) {
|
||||
public static DataType getFloatDataType(int rawFormatByteSize, DataTypeManager dtm) {
|
||||
if (rawFormatByteSize < 1) {
|
||||
return DefaultDataType.dataType;
|
||||
}
|
||||
if (dtm != null) {
|
||||
DataOrganization dataOrganization = dtm.getDataOrganization();
|
||||
if (dataOrganization != null) {
|
||||
if (size == dataOrganization.getFloatSize()) {
|
||||
if (rawFormatByteSize == dataOrganization.getFloatSize()) {
|
||||
return FloatDataType.dataType.clone(dtm);
|
||||
}
|
||||
if (size == dataOrganization.getDoubleSize()) {
|
||||
if (rawFormatByteSize == dataOrganization.getDoubleSize()) {
|
||||
return DoubleDataType.dataType.clone(dtm);
|
||||
}
|
||||
if (size == dataOrganization.getLongDoubleSize()) {
|
||||
if (rawFormatByteSize == dataOrganization.getLongDoubleSize()) {
|
||||
return LongDoubleDataType.dataType.clone(dtm);
|
||||
}
|
||||
}
|
||||
}
|
||||
DataType dt = getFloatTypes().get(size);
|
||||
DataType dt = getFloatTypes().get(rawFormatByteSize);
|
||||
if (dt == null) {
|
||||
return Undefined.getUndefinedDataType(size);
|
||||
return Undefined.getUndefinedDataType(rawFormatByteSize);
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all built-in float data-types
|
||||
* Returns all built-in floating-point data types
|
||||
*
|
||||
* @param dtm optional program data-type manager, if specified generic data-types will be
|
||||
* returned in place of fixed-sized data-types.
|
||||
* @return array of floating-point data types
|
||||
*/
|
||||
public static AbstractFloatDataType[] getFloatDataTypes(DataTypeManager dtm) {
|
||||
TreeMap<Integer, AbstractFloatDataType> floatMap = getFloatTypes();
|
|
@ -0,0 +1,48 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.data.floats;
|
||||
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.util.classfinder.ClassTranslator;
|
||||
|
||||
public class Float128DataType extends AbstractFloatDataType {
|
||||
|
||||
static {
|
||||
// remap old byte-sized float to this bit-sized equivalent
|
||||
ClassTranslator.put(
|
||||
"ghidra.program.model.data.Float16DataType", Float128DataType.class.getName());
|
||||
}
|
||||
|
||||
public static final Float128DataType dataType = new Float128DataType();
|
||||
|
||||
public Float128DataType() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public Float128DataType(DataTypeManager dtm) {
|
||||
super("float128", 16, dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType clone(DataTypeManager dtm) {
|
||||
if (dtm == getDataTypeManager()) {
|
||||
return this;
|
||||
}
|
||||
return new Float128DataType(dtm);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -14,10 +13,20 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.data;
|
||||
package ghidra.program.model.data.floats;
|
||||
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.util.classfinder.ClassTranslator;
|
||||
|
||||
public class Float16DataType extends AbstractFloatDataType {
|
||||
|
||||
static {
|
||||
// remap old byte-sized float to this bit-sized equivalent
|
||||
ClassTranslator.put(
|
||||
"ghidra.program.model.data.Float2DataType", Float16DataType.class.getName());
|
||||
}
|
||||
|
||||
public static final Float16DataType dataType = new Float16DataType();
|
||||
|
||||
public Float16DataType() {
|
||||
|
@ -25,7 +34,7 @@ public class Float16DataType extends AbstractFloatDataType {
|
|||
}
|
||||
|
||||
public Float16DataType(DataTypeManager dtm) {
|
||||
super("float16", dtm);
|
||||
super("float16", 2, dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -36,9 +45,4 @@ public class Float16DataType extends AbstractFloatDataType {
|
|||
return new Float16DataType(dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return 16;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -14,18 +13,28 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.data;
|
||||
package ghidra.program.model.data.floats;
|
||||
|
||||
public class Float10DataType extends AbstractFloatDataType {
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.util.classfinder.ClassTranslator;
|
||||
|
||||
public static final Float10DataType dataType = new Float10DataType();
|
||||
public class Float32DataType extends AbstractFloatDataType {
|
||||
|
||||
public Float10DataType() {
|
||||
static {
|
||||
// remap old byte-sized float to this bit-sized equivalent
|
||||
ClassTranslator.put(
|
||||
"ghidra.program.model.data.Float4DataType", Float32DataType.class.getName());
|
||||
}
|
||||
|
||||
public static final Float32DataType dataType = new Float32DataType();
|
||||
|
||||
public Float32DataType() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public Float10DataType(DataTypeManager dtm) {
|
||||
super("float10", dtm);
|
||||
public Float32DataType(DataTypeManager dtm) {
|
||||
super("float32", 4, dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -33,12 +42,7 @@ public class Float10DataType extends AbstractFloatDataType {
|
|||
if (dtm == getDataTypeManager()) {
|
||||
return this;
|
||||
}
|
||||
return new Float10DataType(dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return 10;
|
||||
return new Float32DataType(dtm);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -14,18 +13,28 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.data;
|
||||
package ghidra.program.model.data.floats;
|
||||
|
||||
public class Float4DataType extends AbstractFloatDataType {
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.util.classfinder.ClassTranslator;
|
||||
|
||||
public static final Float4DataType dataType = new Float4DataType();
|
||||
public class Float64DataType extends AbstractFloatDataType {
|
||||
|
||||
public Float4DataType() {
|
||||
static {
|
||||
// remap old byte-sized float to this bit-sized equivalent
|
||||
ClassTranslator.put(
|
||||
"ghidra.program.model.data.Float8DataType", Float64DataType.class.getName());
|
||||
}
|
||||
|
||||
public static final Float64DataType dataType = new Float64DataType();
|
||||
|
||||
public Float64DataType() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public Float4DataType(DataTypeManager dtm) {
|
||||
super("float4", dtm);
|
||||
public Float64DataType(DataTypeManager dtm) {
|
||||
super("float64", 8, dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -33,12 +42,7 @@ public class Float4DataType extends AbstractFloatDataType {
|
|||
if (dtm == getDataTypeManager()) {
|
||||
return this;
|
||||
}
|
||||
return new Float4DataType(dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return 4;
|
||||
return new Float64DataType(dtm);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -14,18 +13,28 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.data;
|
||||
package ghidra.program.model.data.floats;
|
||||
|
||||
public class Float2DataType extends AbstractFloatDataType {
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.util.classfinder.ClassTranslator;
|
||||
|
||||
public static final Float2DataType dataType = new Float2DataType();
|
||||
public class Float80DataType extends AbstractFloatDataType {
|
||||
|
||||
public Float2DataType() {
|
||||
static {
|
||||
// remap old byte-sized float to this bit-sized equivalent
|
||||
ClassTranslator.put(
|
||||
"ghidra.program.model.data.Float10DataType", Float80DataType.class.getName());
|
||||
}
|
||||
|
||||
public static final Float80DataType dataType = new Float80DataType();
|
||||
|
||||
public Float80DataType() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public Float2DataType(DataTypeManager dtm) {
|
||||
super("float2", dtm);
|
||||
public Float80DataType(DataTypeManager dtm) {
|
||||
super("float80", 10, dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -33,12 +42,7 @@ public class Float2DataType extends AbstractFloatDataType {
|
|||
if (dtm == getDataTypeManager()) {
|
||||
return this;
|
||||
}
|
||||
return new Float2DataType(dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return 2;
|
||||
return new Float80DataType(dtm);
|
||||
}
|
||||
|
||||
}
|
|
@ -26,6 +26,7 @@ import ghidra.app.plugin.processors.sleigh.VarnodeData;
|
|||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.floats.AbstractFloatDataType;
|
||||
import ghidra.program.model.pcode.*;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.xml.SpecXmlUtils;
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.util.*;
|
|||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.floats.AbstractFloatDataType;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.pcode.Varnode;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
|
|
|
@ -18,7 +18,7 @@ package ghidra.program.model.pcode;
|
|||
import java.io.IOException;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.AbstractFloatDataType;
|
||||
import ghidra.program.model.data.floats.AbstractFloatDataType;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.listing.VariableStorage;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
|
|
|
@ -66,6 +66,11 @@ public class PartialUnion extends AbstractDataType {
|
|||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlignedLength() {
|
||||
return getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Partial Union (internal)";
|
||||
|
|
|
@ -28,6 +28,7 @@ import ghidra.program.database.data.PointerTypedefInspector;
|
|||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
import ghidra.program.model.data.floats.AbstractFloatDataType;
|
||||
import ghidra.program.model.lang.CompilerSpec;
|
||||
import ghidra.program.model.lang.DecompilerLanguage;
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
@ -249,6 +250,7 @@ public class PcodeDataTypeManager {
|
|||
else if (meta.equals("float")) {
|
||||
int size = (int) decoder.readSignedInteger(ATTRIB_SIZE);
|
||||
decoder.closeElement(el);
|
||||
// NOTE: Float lookup by length must use "raw" encoding size since
|
||||
return AbstractFloatDataType.getFloatDataType(size, progDataTypes);
|
||||
}
|
||||
else if (meta.equals("partunion")) {
|
||||
|
|
|
@ -20,6 +20,9 @@ import static org.junit.Assert.*;
|
|||
import org.junit.Test;
|
||||
|
||||
import generic.test.AbstractGTest;
|
||||
import ghidra.pcode.floatformat.*;
|
||||
import ghidra.program.model.data.floats.Float32DataType;
|
||||
import ghidra.program.model.data.floats.Float64DataType;
|
||||
import ghidra.program.model.mem.ByteMemBufferImpl;
|
||||
import ghidra.util.LittleEndianDataConverter;
|
||||
|
||||
|
@ -34,106 +37,110 @@ public class FloatDataTypeTest extends AbstractGTest {
|
|||
@Test
|
||||
public void testFloat4Extremes() {
|
||||
|
||||
FloatFormat ff = FloatFormatFactory.getFloatFormat(4);
|
||||
|
||||
int bits = Float.floatToRawIntBits(Float.NaN);
|
||||
byte[] bytes = getBytes(bits, 4);
|
||||
Object value =
|
||||
Float4DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals(Float.NaN, value);
|
||||
Float32DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals(ff.getBigNaN(false), value);
|
||||
|
||||
bits = Float.floatToRawIntBits(Float.POSITIVE_INFINITY);
|
||||
bytes = getBytes(bits, 4);
|
||||
value =
|
||||
Float4DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals(Float.POSITIVE_INFINITY, value);
|
||||
Float32DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals(ff.getBigInfinity(false), value);
|
||||
|
||||
bits = Float.floatToRawIntBits(Float.NEGATIVE_INFINITY);
|
||||
bytes = getBytes(bits, 4);
|
||||
value =
|
||||
Float4DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals(Float.NEGATIVE_INFINITY, value);
|
||||
Float32DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals(ff.getBigInfinity(true), value);
|
||||
|
||||
bits = Float.floatToRawIntBits(0F);
|
||||
bytes = getBytes(bits, 4);
|
||||
value =
|
||||
Float4DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals(0F, value);
|
||||
Float32DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals("0.0", ff.toDecimalString((BigFloat) value));
|
||||
|
||||
bits = Float.floatToRawIntBits(1F);
|
||||
bytes = getBytes(bits, 4);
|
||||
value =
|
||||
Float4DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals(1F, value);
|
||||
Float32DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals("1.0", ff.toDecimalString((BigFloat) value));
|
||||
|
||||
bits = Float.floatToRawIntBits(-1F);
|
||||
bytes = getBytes(bits, 4);
|
||||
value =
|
||||
Float4DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals(-1F, value);
|
||||
Float32DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals("-1.0", ff.toDecimalString((BigFloat) value));
|
||||
|
||||
bits = Float.floatToRawIntBits(555.555F);
|
||||
bytes = getBytes(bits, 4);
|
||||
value =
|
||||
Float4DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals(555.555F, value);
|
||||
Float32DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals("555.55499", ff.toDecimalString((BigFloat) value, true));
|
||||
|
||||
bits = Float.floatToRawIntBits(-555.555F);
|
||||
bytes = getBytes(bits, 4);
|
||||
value =
|
||||
Float4DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals(-555.555F, value);
|
||||
Float32DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals("-555.55499", ff.toDecimalString((BigFloat) value, true));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFloat8Extremes() {
|
||||
|
||||
FloatFormat ff = FloatFormatFactory.getFloatFormat(8);
|
||||
|
||||
long bits = Double.doubleToRawLongBits(Double.NaN);
|
||||
byte[] bytes = getBytes(bits, 8);
|
||||
Object value =
|
||||
Float8DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals(Double.NaN, value);
|
||||
Float64DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals(ff.getBigNaN(false), value);
|
||||
|
||||
bits = Double.doubleToRawLongBits(Double.POSITIVE_INFINITY);
|
||||
bytes = getBytes(bits, 8);
|
||||
value =
|
||||
Float8DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals(Double.POSITIVE_INFINITY, value);
|
||||
Float64DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals(ff.getBigInfinity(false), value);
|
||||
|
||||
bits = Double.doubleToRawLongBits(Double.NEGATIVE_INFINITY);
|
||||
bytes = getBytes(bits, 8);
|
||||
value =
|
||||
Float8DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals(Double.NEGATIVE_INFINITY, value);
|
||||
Float64DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals(ff.getBigInfinity(true), value);
|
||||
|
||||
bits = Double.doubleToRawLongBits(0D);
|
||||
bytes = getBytes(bits, 8);
|
||||
value =
|
||||
Float8DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals(0D, value);
|
||||
Float64DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals("0.0", ff.toDecimalString((BigFloat) value));
|
||||
|
||||
bits = Double.doubleToRawLongBits(1D);
|
||||
bytes = getBytes(bits, 8);
|
||||
value =
|
||||
Float8DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals(1D, value);
|
||||
Float64DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals("1.0", ff.toDecimalString((BigFloat) value));
|
||||
|
||||
bits = Double.doubleToRawLongBits(-1D);
|
||||
bytes = getBytes(bits, 8);
|
||||
value =
|
||||
Float8DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals(-1D, value);
|
||||
Float64DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals("-1.0", ff.toDecimalString((BigFloat) value));
|
||||
|
||||
bits = Double.doubleToRawLongBits(555.555D);
|
||||
bytes = getBytes(bits, 8);
|
||||
value =
|
||||
Float8DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals(555.555D, value);
|
||||
Float64DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals("555.5549999999999", ff.toDecimalString((BigFloat) value, true));
|
||||
|
||||
bits = Double.doubleToRawLongBits(-555.555D);
|
||||
bytes = getBytes(bits, 8);
|
||||
value =
|
||||
Float8DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals(-555.555D, value);
|
||||
Float64DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, false), null, 10);
|
||||
assertEquals("-555.5549999999999", ff.toDecimalString((BigFloat) value, true));
|
||||
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,89 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import java.math.*;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import generic.test.AbstractGTest;
|
||||
import ghidra.pcode.floatformat.FloatFormat;
|
||||
import ghidra.program.model.mem.ByteMemBufferImpl;
|
||||
|
||||
public class Float10DataTypeTest extends AbstractGTest {
|
||||
|
||||
@Test
|
||||
public void testGetValue() {
|
||||
|
||||
byte[] bytes = bytes(0x7f, 0xff, 0, 0, 0, 0, 0, 0, 0, 0); // 0x7fff0000000000000000 = +infinity
|
||||
Object value =
|
||||
Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
|
||||
Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, value);
|
||||
|
||||
bytes = bytes(0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0); // 0xffff0000000000000000 = -infinity
|
||||
value =
|
||||
Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
|
||||
Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, value);
|
||||
|
||||
bytes = bytes(0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0); // 0x7fff8000000000000000 = NaN
|
||||
value =
|
||||
Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
|
||||
Assert.assertEquals(FloatFormat.BIG_NaN, value);
|
||||
|
||||
// Really small values
|
||||
|
||||
MathContext mc = new MathContext(18, RoundingMode.UP);
|
||||
|
||||
bytes = bytes(0, 1, 0x80, 0, 0, 0, 0, 0, 0, 0); // 0x00018000000000000000 = approaches 0
|
||||
value =
|
||||
Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
|
||||
Assert.assertEquals("5.04315471466814026E-4932", ((BigDecimal) value).round(mc).toString());
|
||||
|
||||
bytes = bytes(0x80, 1, 0x80, 0, 0, 0, 0, 0, 0, 0); // 0x00018000000000000000 = approaches 0
|
||||
value =
|
||||
Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
|
||||
Assert.assertEquals("-5.04315471466814026E-4932",
|
||||
((BigDecimal) value).round(mc).toString());
|
||||
|
||||
// Really big values
|
||||
|
||||
bytes = bytes(0x7f, 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0); // 0x7ffe8000000000000000 = approaches +infinity
|
||||
value =
|
||||
Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
|
||||
Assert.assertEquals("8.92298621517923824E+4931", ((BigDecimal) value).round(mc).toString());
|
||||
|
||||
bytes = bytes(0xff, 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0); // 0x7ffe8000000000000000 = approaches -infinity
|
||||
value =
|
||||
Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
|
||||
Assert.assertEquals("-8.92298621517923824E+4931",
|
||||
((BigDecimal) value).round(mc).toString());
|
||||
|
||||
// Values within the range of Double
|
||||
|
||||
bytes = bytes(0x40, 1, 0x20, 0, 0, 0, 0, 0, 0, 0); // 0x40002000000000000000 = approaches -infinity
|
||||
value =
|
||||
Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
|
||||
Assert.assertEquals(BigDecimal.valueOf(4.5), ((BigDecimal) value).stripTrailingZeros());
|
||||
|
||||
bytes = bytes(0xc0, 1, 0x20, 0, 0, 0, 0, 0, 0, 0); // 0x40002000000000000000 = approaches -infinity
|
||||
value =
|
||||
Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
|
||||
Assert.assertEquals(BigDecimal.valueOf(-4.5), ((BigDecimal) value).stripTrailingZeros());
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import generic.test.AbstractGTest;
|
||||
import ghidra.pcode.floatformat.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.floats.Float80DataType;
|
||||
import ghidra.program.model.mem.ByteMemBufferImpl;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
|
||||
public class Float80DataTypeTest extends AbstractGTest {
|
||||
|
||||
@Test
|
||||
public void testGetValue() {
|
||||
|
||||
FloatFormat ff = FloatFormatFactory.getFloatFormat(10);
|
||||
|
||||
byte[] bytes = bytes(0x7f, 0xff, 0, 0, 0, 0, 0, 0, 0, 0); // 0x7fff0000000000000000 = +infinity
|
||||
BigFloat value =
|
||||
Float80DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
|
||||
Assert.assertEquals(ff.getBigInfinity(false), value);
|
||||
Assert.assertEquals("+Infinity", ff.toDecimalString(value, true));
|
||||
|
||||
bytes = bytes(0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0); // 0xffff0000000000000000 = -infinity
|
||||
value =
|
||||
Float80DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
|
||||
Assert.assertEquals(ff.getBigInfinity(true), value);
|
||||
Assert.assertEquals("-Infinity", ff.toDecimalString(value, true));
|
||||
|
||||
bytes = bytes(0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0); // 0x7fff8000000000000000 = NaN
|
||||
value =
|
||||
Float80DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
|
||||
Assert.assertEquals(ff.getBigNaN(false), value);
|
||||
Assert.assertEquals("NaN", ff.toDecimalString(value, true));
|
||||
|
||||
// small values
|
||||
// initially produced by gcc for little-edian then byte-reversed here
|
||||
|
||||
bytes = bytes(0x3c, 1, 0x80, 0, 0, 0, 0, 0, 0, 0);
|
||||
value =
|
||||
Float80DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
|
||||
Assert.assertEquals("2.22507385850720138E-308",
|
||||
ff.toDecimalString(value, true));
|
||||
|
||||
bytes = bytes(0xbc, 1, 0x80, 0, 0, 0, 0, 0, 0, 0);
|
||||
value =
|
||||
Float80DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
|
||||
Assert.assertEquals("-2.22507385850720138E-308",
|
||||
ff.toDecimalString(value, true));
|
||||
|
||||
// Really small values - subnormal minimum for decode only - approaches zero
|
||||
|
||||
bytes = bytes(0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
|
||||
value =
|
||||
Float80DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
|
||||
assertEquals(ff.minValue, value);
|
||||
Assert.assertEquals("3.6E-4951", ff.toDecimalString(value, true));
|
||||
|
||||
bytes = bytes(0x80, 0, 0, 0, 0, 0, 0, 0, 0, 1);
|
||||
value =
|
||||
Float80DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
|
||||
Assert.assertEquals("-3.6E-4951", ff.toDecimalString(value, true));
|
||||
|
||||
// Really big values maximum - approaches -infinity
|
||||
|
||||
bytes = bytes(0x7f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
|
||||
value =
|
||||
Float80DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
|
||||
assertEquals(ff.maxValue, value);
|
||||
Assert.assertEquals("1.18973149535723177E+4932", ff.toDecimalString(value, true));
|
||||
|
||||
bytes = bytes(0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
|
||||
value =
|
||||
Float80DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
|
||||
Assert.assertEquals("-1.18973149535723177E+4932", ff.toDecimalString(value, true));
|
||||
|
||||
// Values within the range of Double
|
||||
|
||||
// pi - 3.14159265358979323
|
||||
// initially produced by gcc for little-edian then byte-reversed here
|
||||
|
||||
bytes = bytes(0x40, 0, 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc0, 0);
|
||||
value =
|
||||
Float80DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
|
||||
Assert.assertEquals("3.14159265358979312", ff.toDecimalString(value, true));
|
||||
|
||||
bytes = bytes(0xc0, 0, 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc0, 0);
|
||||
value =
|
||||
Float80DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
|
||||
Assert.assertEquals("-3.14159265358979312", ff.toDecimalString(value, true));
|
||||
|
||||
}
|
||||
|
||||
private static MemBuffer buf(boolean bigEndian, int... vals) {
|
||||
return new ByteMemBufferImpl(Address.NO_ADDRESS, bytes(vals), bigEndian);
|
||||
}
|
||||
|
||||
private static final MemBuffer BE = buf(true, 0);
|
||||
|
||||
@Test
|
||||
public void testEncodeValue() throws Exception {
|
||||
|
||||
FloatFormat ff = FloatFormatFactory.getFloatFormat(10);
|
||||
|
||||
byte[] bytes = bytes(0x7f, 0xff, 0, 0, 0, 0, 0, 0, 0, 0); // 0x7fff0000000000000000 = +infinity
|
||||
assertArrayEquals(bytes,
|
||||
Float80DataType.dataType.encodeValue(ff.getBigFloat("+Infinity"), BE, null, -1));
|
||||
|
||||
bytes = bytes(0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0); // 0xffff0000000000000000 = -infinity
|
||||
assertArrayEquals(bytes,
|
||||
Float80DataType.dataType.encodeValue(ff.getBigFloat("-Infinity"), BE, null, -1));
|
||||
|
||||
bytes = bytes(0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0); // 0x7fff8000000000000000 = NaN
|
||||
assertArrayEquals(bytes,
|
||||
Float80DataType.dataType.encodeValue(ff.getBigFloat("NaN"), BE, null, -1));
|
||||
|
||||
// NOTE: Multiple byte[] values can render the same decimal string
|
||||
|
||||
bytes = Float80DataType.dataType
|
||||
.encodeValue(ff.getBigFloat("5.04315471466814026E-4932"), BE, null, -1);
|
||||
assertEquals("5.04315471466814026E-4932", Float80DataType.dataType
|
||||
.getRepresentation(new ByteMemBufferImpl(null, bytes, true), null, -1));
|
||||
|
||||
bytes = Float80DataType.dataType.encodeValue(ff.getBigFloat("-5.04315471466814026E-4932"),
|
||||
BE, null, -1);
|
||||
assertEquals("-5.04315471466814026E-4932", Float80DataType.dataType
|
||||
.getRepresentation(new ByteMemBufferImpl(null, bytes, true), null, -1));
|
||||
|
||||
bytes = Float80DataType.dataType
|
||||
.encodeValue(ff.getBigFloat("8.92298621517923824E+4931"), BE, null, -1);
|
||||
assertEquals("8.92298621517923824E+4931", Float80DataType.dataType
|
||||
.getRepresentation(new ByteMemBufferImpl(null, bytes, true), null, -1));
|
||||
|
||||
bytes = Float80DataType.dataType.encodeValue(ff.getBigFloat("-8.92298621517923824E+4931"),
|
||||
BE, null, -1);
|
||||
assertEquals("-8.92298621517923824E+4931", Float80DataType.dataType
|
||||
.getRepresentation(new ByteMemBufferImpl(null, bytes, true), null, -1));
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -134,6 +134,11 @@ public class StubDataType implements DataType {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlignedLength() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isZeroLength() {
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue