Merge remote-tracking branch

'origin/GT-3512_dev747368_dataconverter_fixes'
This commit is contained in:
ghidra1 2020-02-21 14:03:30 -05:00
commit 45778b0117
43 changed files with 635 additions and 758 deletions

View file

@ -172,8 +172,7 @@ public class Emulator {
* @param restore if true restore modified registers within the register space only
*/
private void initRegisters(boolean restore) {
DataConverter conv =
language.isBigEndian() ? new BigEndianDataConverter() : new LittleEndianDataConverter();
DataConverter conv = DataConverter.getInstance(language.isBigEndian());
Set<String> keys = mstate.getKeys();
for (String key : keys) {
List<byte[]> vals = mstate.getVals(key);

View file

@ -31,7 +31,7 @@ abstract class RefList extends DatabaseObject {
static volatile int BIG_REFLIST_THRESHOLD = 1700;
protected static DataConverter converter = new BigEndianDataConverter();
protected static DataConverter converter = BigEndianDataConverter.INSTANCE;
protected Address address;
protected RecordAdapter adapter;

View file

@ -327,7 +327,7 @@ public class GenericAddress implements Address {
public String toString(boolean showAddressSpace, int minNumDigits) {
boolean stackFormat = false;
StringBuffer buf = new StringBuffer();
StringBuilder buf = new StringBuilder();
if (addrSpace.isStackSpace()) {
stackFormat = true;
buf.append("Stack[");

View file

@ -24,6 +24,7 @@ import ghidra.program.model.address.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.*;
import ghidra.program.model.symbol.*;
import ghidra.util.DataConverter;
/**
* Basic implementation for a pointer dataType
@ -287,7 +288,7 @@ public class PointerDataType extends BuiltIn implements Pointer {
@Override
public String getDescription() {
StringBuffer sbuf = new StringBuffer();
StringBuilder sbuf = new StringBuilder();
if (length > 0) {
sbuf.append(Integer.toString(8 * length));
sbuf.append("-bit ");
@ -342,6 +343,7 @@ public class PointerDataType extends BuiltIn implements Pointer {
if (buf.getAddress() instanceof SegmentedAddress) {
try {
// NOTE: conversion assumes a little-endian space
return getSegmentedAddressValue(buf, size);
}
catch (AddressOutOfBoundsException e) {
@ -362,21 +364,7 @@ public class PointerDataType extends BuiltIn implements Pointer {
return null;
}
boolean isBigEndian = buf.isBigEndian(); // ENDIAN.isBigEndian(settings, buf);
if (!isBigEndian) {
byte[] flipped = new byte[size];
for (int i = 0; i < size; i++) {
flipped[i] = bytes[size - i - 1];
}
bytes = flipped;
}
// Use long when possible
long val = 0;
for (byte b : bytes) {
val = (val << 8) + (b & 0x0ffL);
}
long val = DataConverter.getInstance(buf.isBigEndian()).getValue(bytes, size);
try {
return targetSpace.getAddress(val, true);
@ -387,22 +375,27 @@ public class PointerDataType extends BuiltIn implements Pointer {
return null;
}
/**
* Read segmented address from memory.
* NOTE: little-endian memory assumed.
* @param buf memory buffer associated with a segmented-address space
* positioned at start of address value to be read
* @param dataLen pointer-length (2 and 4-byte pointers supported)
* @return address value returned as segmented Address object or null
* for unsupported pointer length or meory access error occurs.
*/
private static Address getSegmentedAddressValue(MemBuffer buf, int dataLen) {
SegmentedAddress a = (SegmentedAddress) buf.getAddress();
int segment = a.getSegment();
int offset = 0;
try {
switch (dataLen) {
case 1:
offset = buf.getByte(0) & 0xff;
case 2: // near pointer
offset = (int) buf.getVarLengthUnsignedInt(0, dataLen);
break;
case 2:
offset = buf.getShort(0) & 0xffff;
break;
case 4:
case 8:
segment = buf.getShort(0) & 0xffff;
offset = buf.getShort(2) & 0xffff;
case 4: // far pointer
segment = buf.getUnsignedShort(0);
offset = buf.getUnsignedShort(2);
break;
default:
return null;

View file

@ -20,6 +20,7 @@ import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.ProcessorContext;
import ghidra.program.model.mem.MemBuffer;
import ghidra.util.DataConverter;
import ghidra.util.classfinder.ClassTranslator;
/**
@ -105,21 +106,7 @@ public class ShiftedAddressDataType extends BuiltIn {
return null;
}
boolean isBigEndian = buf.isBigEndian(); // ENDIAN.isBigEndian(settings, buf);
if (!isBigEndian) {
byte[] flipped = new byte[size];
for (int i = 0; i < size; i++) {
flipped[i] = bytes[size - i - 1];
}
bytes = flipped;
}
// Use long when possible
long val = 0;
for (byte b : bytes) {
val = (val << 8) + (b & 0x0ffL);
}
long val = DataConverter.getInstance(buf.isBigEndian()).getValue(bytes, size);
val = val << shift;

View file

@ -18,8 +18,7 @@ package ghidra.program.model.mem;
import java.math.BigInteger;
import ghidra.program.model.address.Address;
import ghidra.util.GhidraBigEndianDataConverter;
import ghidra.util.GhidraLittleEndianDataConverter;
import ghidra.util.GhidraDataConverter;
/**
* Simple byte buffer implementation of the memBuffer. Since there is no
@ -29,9 +28,9 @@ import ghidra.util.GhidraLittleEndianDataConverter;
*/
public class ByteMemBufferImpl implements MemBuffer {
private final GhidraDataConverter converter;
private byte[] bytes;
private Address addr;
private final boolean isBigEndian;
/**
* Construct a ByteMemBufferImpl object
@ -42,23 +41,7 @@ public class ByteMemBufferImpl implements MemBuffer {
public ByteMemBufferImpl(Address addr, byte[] bytes, boolean isBigEndian) {
this.addr = addr;
this.bytes = bytes;
this.isBigEndian = isBigEndian;
}
/**
* Convenience constructor using varargs for specifying byte values.
* @param addr the address to associate with the bytes
* @param isBigEndian true for BigEndian, false for LittleEndian.
* @param byteValues varargs for specifying the individual byte values. The int argument
* will be truncated to a byte value.
*/
public ByteMemBufferImpl(Address addr, boolean isBigEndian, int... byteValues) {
this.addr = addr;
this.isBigEndian = isBigEndian;
bytes = new byte[byteValues.length];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) byteValues[i];
}
this.converter = GhidraDataConverter.getInstance(isBigEndian);
}
/**
@ -96,42 +79,30 @@ public class ByteMemBufferImpl implements MemBuffer {
System.arraycopy(bytes, offset, b, 0, len);
return len;
}
@Override
public boolean isBigEndian() {
return isBigEndian;
return converter.isBigEndian();
}
@Override
public short getShort(int offset) throws MemoryAccessException {
if (isBigEndian) {
return GhidraBigEndianDataConverter.INSTANCE.getShort(this, offset);
}
return GhidraLittleEndianDataConverter.INSTANCE.getShort(this, offset);
return converter.getShort(this, offset);
}
@Override
public int getInt(int offset) throws MemoryAccessException {
if (isBigEndian) {
return GhidraBigEndianDataConverter.INSTANCE.getInt(this, offset);
}
return GhidraLittleEndianDataConverter.INSTANCE.getInt(this, offset);
return converter.getInt(this, offset);
}
@Override
public long getLong(int offset) throws MemoryAccessException {
if (isBigEndian) {
return GhidraBigEndianDataConverter.INSTANCE.getLong(this, offset);
}
return GhidraLittleEndianDataConverter.INSTANCE.getLong(this, offset);
return converter.getLong(this, offset);
}
@Override
public BigInteger getBigInteger(int offset, int size, boolean signed)
throws MemoryAccessException {
if (isBigEndian) {
return GhidraBigEndianDataConverter.INSTANCE.getBigInteger(this, offset, size, signed);
}
return GhidraLittleEndianDataConverter.INSTANCE.getBigInteger(this, offset, size, signed);
return converter.getBigInteger(this, offset, size, signed);
}
}

View file

@ -23,37 +23,54 @@ import ghidra.program.model.mem.MemoryAccessException;
public interface GhidraDataConverter extends DataConverter {
/**
* Generate a little-endian short value by invoking buf.getBytes at the specified offset.
* @param buf
* @param offset
* @return little-endian short value
* Returns the correct GhidraDataConverter static instance for the requested endian-ness.
*
* @param isBigEndian boolean flag, true means big endian
* @return static GhidraDataConverter instance
*/
public static GhidraDataConverter getInstance(boolean isBigEndian) {
return isBigEndian ? GhidraBigEndianDataConverter.INSTANCE
: GhidraLittleEndianDataConverter.INSTANCE;
}
/**
* Generate a short value by invoking buf.getBytes at the specified offset.
*
* @param buf MemBuffer source of bytes
* @param offset offset in mem buffer to read
* @return short value
* @throws MemoryAccessException if failed to read 2-bytes at the specified offset
*/
public short getShort(MemBuffer buf, int offset) throws MemoryAccessException;
/**
* Generate a little-endian int value by invoking buf.getBytes at the specified offset.
* @param buf
* @param offset
* @return little-endian int value
* Generate a int value by invoking buf.getBytes at the specified offset.
*
* @param buf MemBuffer source of bytes
* @param offset offset in mem buffer to read
* @return int value
* @throws MemoryAccessException if failed to read 4-bytes at the specified offset
*/
public int getInt(MemBuffer buf, int offset) throws MemoryAccessException;
/**
* Generate a little-endian long value by invoking buf.getBytes at the specified offset.
* @param buf
* @param offset
* @return little-endian long value
* Generate a long value by invoking buf.getBytes at the specified offset.
*
* @param buf MemBuffer source of bytes
* @param offset offset in mem buffer to read
* @return long value
* @throws MemoryAccessException if failed to read 8-bytes at the specified offset
*/
public long getLong(MemBuffer buf, int offset) throws MemoryAccessException;
/**
* Generate a little-endian BigInteger value by invoking buf.getBytes at the specified offset.
* @param buf
* @param offset
* @return little-endian BigInteger value
* Generate a BigInteger value by invoking buf.getBytes at the specified offset.
*
* @param buf MemBuffer source of bytes
* @param offset offset in mem buffer to read
* @param size number of bytes
* @param signed boolean flag
* @return BigInteger value
* @throws MemoryAccessException if failed to read specified number of bytes
* at the specified offset
*/

View file

@ -15,21 +15,19 @@
*/
package ghidra.program.model.data;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.*;
import org.junit.Test;
import generic.test.AbstractGTest;
import ghidra.program.model.mem.ByteMemBufferImpl;
import ghidra.util.LittleEndianDataConverter;
public class FloatDataTypeTest extends AbstractGTest {
private byte[] getBytes(long value, int size) {
byte[] bytes = new byte[size];
for (int i = 0; i < size; i++) {
bytes[i] = (byte) value;
value >>= 8;
}
LittleEndianDataConverter.INSTANCE.getBytes(value, size, bytes, 0);
return bytes;
}

View file

@ -26,12 +26,8 @@ import ghidra.program.model.mem.ByteMemBufferImpl;
public class ArrayStringableTest extends AbstractGTest {
private ByteMemBufferImpl mb(boolean isBE, int... values) {
byte[] bytes = new byte[values.length];
for (int i = 0; i < values.length; i++) {
bytes[i] = (byte) values[i];
}
GenericAddressSpace gas = new GenericAddressSpace("test", 32, AddressSpace.TYPE_RAM, 1);
return new ByteMemBufferImpl(gas.getAddress(0), bytes, isBE);
return new ByteMemBufferImpl(gas.getAddress(0), bytes(values), isBE);
}
private SettingsBuilder newset() {

View file

@ -15,7 +15,7 @@
*/
package ghidra.program.model.data;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.*;
import org.junit.Test;
@ -157,8 +157,9 @@ public class BitFieldDataTypeTest extends AbstractGTest {
assertEquals("5", getDecimalRepresentation(unsignedBitField(4, 0), 0x55));
}
private String getRepresentation(BitFieldDataType bitField, int... bytes) throws Exception {
MemBuffer membuf = membuf(bytes);
private String getRepresentation(BitFieldDataType bitField, int... unsignedBytes)
throws Exception {
MemBuffer membuf = membuf(unsignedBytes);
return bitField.getRepresentation(membuf, null, 4);
}
@ -184,8 +185,8 @@ public class BitFieldDataTypeTest extends AbstractGTest {
return new BitFieldDataType(UnsignedIntegerDataType.dataType, size, offset);
}
private MemBuffer membuf(int... bytes) throws Exception {
return new ByteMemBufferImpl(null, true, bytes);
private MemBuffer membuf(int... unsignedBytes) throws Exception {
return new ByteMemBufferImpl(null, bytes(unsignedBytes), true);
}
}

View file

@ -36,12 +36,8 @@ import ghidra.program.model.mem.ByteMemBufferImpl;
public class CharDataTypesRenderTest extends AbstractGTest {
private ByteMemBufferImpl mb(boolean isBE, int... values) {
byte[] bytes = new byte[values.length];
for (int i = 0; i < values.length; i++) {
bytes[i] = (byte) values[i];
}
GenericAddressSpace gas = new GenericAddressSpace("test", 32, AddressSpace.TYPE_RAM, 1);
return new ByteMemBufferImpl(gas.getAddress(0), bytes, isBE);
return new ByteMemBufferImpl(gas.getAddress(0), bytes(values), isBE);
}
private SettingsBuilder newset() {

View file

@ -29,53 +29,53 @@ public class Float10DataTypeTest extends AbstractGTest {
@Test
public void testGetValue() {
byte[] bytes = new byte[] { 0x7f, (byte) 0xff, 0, 0, 0, 0, 0, 0, 0, 0 }; // 0x7fff0000000000000000 = +infinity
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 = new byte[] { (byte) 0xff, (byte) 0xff, 0, 0, 0, 0, 0, 0, 0, 0 }; // 0xffff0000000000000000 = -infinity
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 = new byte[] { (byte) 0x7f, (byte) 0xff, (byte) 0x80, 0, 0, 0, 0, 0, 0, 0 }; // 0x7fff8000000000000000 = NaN
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
bytes = new byte[] { 0, 1, (byte) 0x80, 0, 0, 0, 0, 0, 0, 0 }; // 0x00018000000000000000 = approaches 0
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", value.toString());
bytes = new byte[] { (byte) 0x80, 1, (byte) 0x80, 0, 0, 0, 0, 0, 0, 0 }; // 0x00018000000000000000 = approaches 0
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", value.toString());
// Really big values
bytes = new byte[] { (byte) 0x7f, (byte) 0xfe, (byte) 0x80, 0, 0, 0, 0, 0, 0, 0 }; // 0x7ffe8000000000000000 = approaches +infinity
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", value.toString());
bytes = new byte[] { (byte) 0xff, (byte) 0xfe, (byte) 0x80, 0, 0, 0, 0, 0, 0, 0 }; // 0x7ffe8000000000000000 = approaches -infinity
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", value.toString());
// Values within the range of Double
bytes = new byte[] { 0x40, 1, 0x20, 0, 0, 0, 0, 0, 0, 0 }; // 0x40002000000000000000 = approaches -infinity
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), value);
bytes = new byte[] { (byte) 0xc0, 1, 0x20, 0, 0, 0, 0, 0, 0, 0 }; // 0x40002000000000000000 = approaches -infinity
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), value);

View file

@ -59,12 +59,8 @@ public class StringDataTypeTest extends AbstractGTest {
}
private ByteMemBufferImpl mb(boolean isBE, int... values) {
byte[] bytes = new byte[values.length];
for (int i = 0; i < values.length; i++) {
bytes[i] = (byte) values[i];
}
GenericAddressSpace gas = new GenericAddressSpace("test", 32, AddressSpace.TYPE_RAM, 1);
return new ByteMemBufferImpl(gas.getAddress(0), bytes, isBE);
return new ByteMemBufferImpl(gas.getAddress(0), bytes(values), isBE);
}
private SettingsBuilder newset() {