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

@ -93,12 +93,7 @@ public class BinaryReader {
* @param isLittleEndian true for little-endian and false for big-endian * @param isLittleEndian true for little-endian and false for big-endian
*/ */
public void setLittleEndian(boolean isLittleEndian) { public void setLittleEndian(boolean isLittleEndian) {
if (isLittleEndian) { converter = DataConverter.getInstance(!isLittleEndian);
converter = new LittleEndianDataConverter();
}
else {
converter = new BigEndianDataConverter();
}
} }
/** /**
@ -664,7 +659,7 @@ public class BinaryReader {
} }
/** /**
* Returns the LONG at <code>index</code>. * Returns the signed LONG at <code>index</code>.
* @param index the index where the LONG begins * @param index the index where the LONG begins
* @return the LONG * @return the LONG
* @exception IOException if an I/O error occurs * @exception IOException if an I/O error occurs
@ -674,6 +669,34 @@ public class BinaryReader {
return converter.getLong(bytes); return converter.getLong(bytes);
} }
/**
* Returns the signed value of the integer (of the specified length) at the specified offset.
*
* @param index offset the offset from the membuffers origin (the address that it is set at)
* @param len the number of bytes that the integer occupies. Valid values are 1 (byte), 2 (short),
* 4 (int), 8 (long)
* @return value of requested length, with sign bit extended, in a long
* @throws IOException
*/
public long readValue(long index, int len) throws IOException {
byte[] bytes = provider.readBytes(index, len);
return converter.getSignedValue(bytes, len);
}
/**
* Returns the unsigned value of the integer (of the specified length) at the specified offset.
*
* @param index offset the offset from the membuffers origin (the address that it is set at)
* @param len the number of bytes that the integer occupies. Valid values are 1 (byte), 2 (short),
* 4 (int), 8 (long)
* @return unsigned value of requested length, in a long
* @throws IOException
*/
public long readUnsignedValue(long index, int len) throws IOException {
byte[] bytes = provider.readBytes(index, len);
return converter.getValue(bytes, len);
}
/** /**
* Returns the BYTE array of <code>nElements</code> * Returns the BYTE array of <code>nElements</code>
* starting at <code>index</code>. * starting at <code>index</code>.

View file

@ -58,8 +58,7 @@ public abstract class AbstractClassicProcessor {
Address address = defaultAddressSpace.getAddress(addressValue); Address address = defaultAddressSpace.getAddress(addressValue);
DataConverter converter = DataConverter converter = DataConverter.getInstance(language.isBigEndian());
language.isBigEndian() ? new BigEndianDataConverter() : new LittleEndianDataConverter();
Symbol symbol = getSymbol(nList); Symbol symbol = getSymbol(nList);

View file

@ -58,8 +58,7 @@ abstract public class AbstractDyldInfoState {
long offset = symbol.getAddress().getOffset(); long offset = symbol.getAddress().getOffset();
DataConverter converter = program.getLanguage().isBigEndian() ? new BigEndianDataConverter() DataConverter converter = DataConverter.getInstance(program.getLanguage().isBigEndian());
: new LittleEndianDataConverter();
byte[] bytes = (program.getDefaultPointerSize() == 8) ? converter.getBytes(offset) byte[] bytes = (program.getDefaultPointerSize() == 8) ? converter.getBytes(offset)
: converter.getBytes((int) offset); : converter.getBytes((int) offset);

View file

@ -40,7 +40,7 @@ public class ImportDataDirectory extends DataDirectory {
private ImportInfo[] imports; private ImportInfo[] imports;
ExportDataDirectory exportDirectory; ExportDataDirectory exportDirectory;
DataConverter conv = new LittleEndianDataConverter(); DataConverter conv = LittleEndianDataConverter.INSTANCE;
static ImportDataDirectory createImportDataDirectory(NTHeader ntHeader, static ImportDataDirectory createImportDataDirectory(NTHeader ntHeader,
FactoryBundledWithBinaryReader reader) throws IOException { FactoryBundledWithBinaryReader reader) throws IOException {

View file

@ -167,10 +167,7 @@ public class GUID {
} }
private DataConverter getDataConverter(MemBuffer buf) { private DataConverter getDataConverter(MemBuffer buf) {
if (buf.isBigEndian()) { return DataConverter.getInstance(buf.isBigEndian());
return new BigEndianDataConverter();
}
return new LittleEndianDataConverter();
} }
@Override @Override

View file

@ -110,9 +110,7 @@ public class GuidDataType extends BuiltIn {
long[] data = new long[4]; long[] data = new long[4];
boolean isBigEndian = ENDIAN.isBigEndian(settings, buf); boolean isBigEndian = ENDIAN.isBigEndian(settings, buf);
DataConverter conv = DataConverter conv = DataConverter.getInstance(isBigEndian);
isBigEndian ? (DataConverter) new BigEndianDataConverter()
: (DataConverter) new LittleEndianDataConverter();
if (buf.getBytes(bytes, 0) != bytes.length) { if (buf.getBytes(bytes, 0) != bytes.length) {
if (guidName != null) { if (guidName != null) {

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -211,9 +210,7 @@ public class GuidUtil {
byte[] bytes = new byte[16]; byte[] bytes = new byte[16];
long[] data = new long[4]; long[] data = new long[4];
boolean isBigEndian = program.getMemory().isBigEndian(); boolean isBigEndian = program.getMemory().isBigEndian();
DataConverter conv = DataConverter conv = DataConverter.getInstance(isBigEndian);
isBigEndian ? (DataConverter) new BigEndianDataConverter()
: (DataConverter) new LittleEndianDataConverter();
try { try {
program.getMemory().getBytes(address, bytes); program.getMemory().getBytes(address, bytes);
@ -254,9 +251,7 @@ public class GuidUtil {
long[] data = new long[4]; long[] data = new long[4];
int[] versionData = new int[2]; int[] versionData = new int[2];
boolean isBigEndian = program.getMemory().isBigEndian(); boolean isBigEndian = program.getMemory().isBigEndian();
DataConverter conv = DataConverter conv = DataConverter.getInstance(isBigEndian);
isBigEndian ? (DataConverter) new BigEndianDataConverter()
: (DataConverter) new LittleEndianDataConverter();
try { try {
program.getMemory().getBytes(address, bytes); program.getMemory().getBytes(address, bytes);

View file

@ -53,7 +53,7 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
// Efficient check to fail fast // Efficient check to fail fast
byte[] magicBytes = provider.readBytes(0, 4); byte[] magicBytes = provider.readBytes(0, 4);
if (!MachConstants.isMagic(new LittleEndianDataConverter().getInt(magicBytes))) { if (!MachConstants.isMagic(LittleEndianDataConverter.INSTANCE.getInt(magicBytes))) {
return loadSpecs; return loadSpecs;
} }

View file

@ -1385,8 +1385,7 @@ public class MachoProgramBuilder {
} }
private DataConverter getDataConverter() { private DataConverter getDataConverter() {
DataConverter dc = program.getLanguage().isBigEndian() ? new BigEndianDataConverter() DataConverter dc = DataConverter.getInstance(program.getLanguage().isBigEndian());
: new LittleEndianDataConverter();
return dc; return dc;
} }

View file

@ -52,7 +52,7 @@ public class MzLoader extends AbstractLibrarySupportLoader {
private final static byte MOVW_DS_OPCODE = (byte) 0xba; private final static byte MOVW_DS_OPCODE = (byte) 0xba;
private static final long MIN_BYTE_LENGTH = 4; private static final long MIN_BYTE_LENGTH = 4;
private DataConverter converter = new LittleEndianDataConverter(); private DataConverter converter = LittleEndianDataConverter.INSTANCE;
@Override @Override
public int getTierPriority() { public int getTierPriority() {

View file

@ -33,7 +33,7 @@ import ghidra.program.model.listing.*;
import ghidra.program.model.mem.*; import ghidra.program.model.mem.*;
import ghidra.program.model.symbol.*; import ghidra.program.model.symbol.*;
import ghidra.program.model.util.CodeUnitInsertionException; import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.util.*; import ghidra.util.DataConverter;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.exception.InvalidInputException; import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
@ -180,13 +180,7 @@ public class OmfLoader extends AbstractLibrarySupportLoader {
ArrayList<OmfFixupRecord> fixups = header.getFixups(); ArrayList<OmfFixupRecord> fixups = header.getFixups();
OmfFixupRecord.FixupState state = OmfFixupRecord.FixupState state =
new OmfFixupRecord.FixupState(header, externsyms, program.getLanguage()); new OmfFixupRecord.FixupState(header, externsyms, program.getLanguage());
DataConverter converter; DataConverter converter = DataConverter.getInstance(!header.isLittleEndian());
if (header.isLittleEndian()) {
converter = new LittleEndianDataConverter();
}
else {
converter = new BigEndianDataConverter();
}
for (OmfFixupRecord fixup : fixups) { for (OmfFixupRecord fixup : fixups) {
state.currentFixupRecord = fixup; state.currentFixupRecord = fixup;

View file

@ -319,7 +319,7 @@ public class PeLoader extends AbstractPeDebugLoader {
space.getAddress(originalImageBase + brdd.getVirtualAddress() + brdd.getSize())); space.getAddress(originalImageBase + brdd.getVirtualAddress() + brdd.getSize()));
AddressRange headerRange = new AddressRangeImpl(space.getAddress(originalImageBase), AddressRange headerRange = new AddressRangeImpl(space.getAddress(originalImageBase),
space.getAddress(originalImageBase + optionalHeader.getSizeOfHeaders())); space.getAddress(originalImageBase + optionalHeader.getSizeOfHeaders()));
DataConverter conv = new LittleEndianDataConverter(); DataConverter conv = LittleEndianDataConverter.INSTANCE;
for (BaseRelocation reloc : relocs) { for (BaseRelocation reloc : relocs) {
if (monitor.isCancelled()) { if (monitor.isCancelled()) {

View file

@ -521,16 +521,9 @@ public class ProgramMemoryUtil {
int addrSize = toAddress.getSize(); int addrSize = toAddress.getSize();
DataConverter dataConverter; DataConverter dataConverter = DataConverter.getInstance(memory.isBigEndian());
byte[] addressBytes = new byte[addrSize / 8]; byte[] addressBytes = new byte[addrSize / 8];
if (isBigEndian) {
dataConverter = new BigEndianDataConverter();
}
else {
dataConverter = new LittleEndianDataConverter();
}
if (toAddress instanceof SegmentedAddress) { if (toAddress instanceof SegmentedAddress) {
// Only search for offset (exclude segment) // Only search for offset (exclude segment)
addressBytes = new byte[2]; addressBytes = new byte[2];

View file

@ -195,9 +195,7 @@ public class FollowFlowProgramBuilder extends ProgramBuilder {
private void setupProgram() throws Exception { private void setupProgram() throws Exception {
dataConverter = dataConverter = DataConverter.getInstance(getProgram().getMemory().isBigEndian());
(getProgram().getMemory().isBigEndian()) ? new BigEndianDataConverter()
: new LittleEndianDataConverter();
createMemory(".text", "0x0", 0x1000); createMemory(".text", "0x0", 0x1000);
createMemory(".data", "0x5000", 0x1000); createMemory(".data", "0x5000", 0x1000);

View file

@ -15,18 +15,14 @@
*/ */
package ghidra.util; package ghidra.util;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.Arrays; import java.util.Arrays;
import org.junit.Assert; import org.junit.*;
import org.junit.Before;
import org.junit.Test;
import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.util.BigEndianDataConverter;
import ghidra.util.DataConverter;
/** /**
* *
@ -38,7 +34,7 @@ import ghidra.util.DataConverter;
*/ */
public class BigEndianConverterTest extends AbstractGhidraHeadedIntegrationTest { public class BigEndianConverterTest extends AbstractGhidraHeadedIntegrationTest {
private byte[] b; private byte[] b;
private DataConverter dc; private DataConverter dc = BigEndianDataConverter.INSTANCE;
/** /**
* Constructor for BigEndianConverterTest. * Constructor for BigEndianConverterTest.
@ -54,7 +50,6 @@ public class BigEndianConverterTest extends AbstractGhidraHeadedIntegrationTest
for (int i = 0; i < b.length; i++) { for (int i = 0; i < b.length; i++) {
b[i] = (byte) i; b[i] = (byte) i;
} }
dc = new BigEndianDataConverter();
} }
@Test @Test
@ -75,6 +70,10 @@ public class BigEndianConverterTest extends AbstractGhidraHeadedIntegrationTest
assertEquals(0x000102L, dc.getValue(b, 3)); assertEquals(0x000102L, dc.getValue(b, 3));
assertEquals(0x0001020304050607L, dc.getValue(b, 8)); assertEquals(0x0001020304050607L, dc.getValue(b, 8));
assertEquals(0x0001L, dc.getSignedValue(b, 2));
assertEquals(0x000102L, dc.getSignedValue(b, 3));
assertEquals(0x0001020304050607L, dc.getSignedValue(b, 8));
assertEquals(0x0203L, dc.getValue(b, 2, 2)); assertEquals(0x0203L, dc.getValue(b, 2, 2));
assertEquals(0x020304L, dc.getValue(b, 2, 3)); assertEquals(0x020304L, dc.getValue(b, 2, 3));
assertEquals(0x0203040506070809L, dc.getValue(b, 2, 8)); assertEquals(0x0203040506070809L, dc.getValue(b, 2, 8));
@ -83,15 +82,21 @@ public class BigEndianConverterTest extends AbstractGhidraHeadedIntegrationTest
assertEquals(0x04050607, dc.getBigInteger(b, 4, 4, true).intValue()); assertEquals(0x04050607, dc.getBigInteger(b, 4, 4, true).intValue());
assertEquals(0x0405060708090a0bL, dc.getBigInteger(b, 4, 8, true).longValue()); assertEquals(0x0405060708090a0bL, dc.getBigInteger(b, 4, 8, true).longValue());
BigInteger bint = BigInteger bint = dc.getBigInteger(bytes(0x01, 0x02, 0xff, 0x03), 2, 2, true);
dc.getBigInteger(new byte[] { 0x01, 0x02, (byte) 0xff, 0x03 }, 2, 2, true);
assertEquals((short) 0xff03, bint.shortValue());// -253 assertEquals((short) 0xff03, bint.shortValue());// -253
assertEquals(0xffffff03, bint.intValue()); assertEquals(0xffffff03, bint.intValue());
bint = dc.getBigInteger(new byte[] { 0x01, 0x02, (byte) 0xff, 0x03 }, 2, 2, false); bint = dc.getBigInteger(bytes(0x01, 0x02, 0xff, 0x03), 2, 2, false);
assertEquals((short) 0xff03, bint.shortValue()); assertEquals((short) 0xff03, bint.shortValue());
assertEquals(0x0000ff03, bint.intValue()); assertEquals(0x0000ff03, bint.intValue());
}
@Test
public void testGetSignedValues() {
assertEquals(Integer.MIN_VALUE, dc.getSignedValue(bytes(0x80, 00, 00, 00), 4));
assertEquals(-0x800000L, dc.getSignedValue(bytes(0x80, 00, 00, 00), 3));
assertEquals(-256, dc.getSignedValue(bytes(0xFF, 00, 00, 00), 2));
} }
@Test @Test

View file

@ -15,14 +15,12 @@
*/ */
package ghidra.util; package ghidra.util;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.Arrays; import java.util.Arrays;
import org.junit.Assert; import org.junit.*;
import org.junit.Before;
import org.junit.Test;
import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.AbstractGhidraHeadedIntegrationTest;
@ -36,7 +34,7 @@ import ghidra.test.AbstractGhidraHeadedIntegrationTest;
*/ */
public class LittleEndianConverterTest extends AbstractGhidraHeadedIntegrationTest { public class LittleEndianConverterTest extends AbstractGhidraHeadedIntegrationTest {
private byte[] b; private byte[] b;
private DataConverter dc; private DataConverter dc = LittleEndianDataConverter.INSTANCE;
/** /**
* Constructor for BigEndianConverterTest. * Constructor for BigEndianConverterTest.
@ -52,7 +50,6 @@ public class LittleEndianConverterTest extends AbstractGhidraHeadedIntegrationTe
for (int i = 0; i < b.length; i++) { for (int i = 0; i < b.length; i++) {
b[i] = (byte) i; b[i] = (byte) i;
} }
dc = new LittleEndianDataConverter();
} }
@Test @Test
@ -73,6 +70,10 @@ public class LittleEndianConverterTest extends AbstractGhidraHeadedIntegrationTe
assertEquals(0x020100L, dc.getValue(b, 3)); assertEquals(0x020100L, dc.getValue(b, 3));
assertEquals(0x0706050403020100L, dc.getValue(b, 8)); assertEquals(0x0706050403020100L, dc.getValue(b, 8));
assertEquals(0x0100L, dc.getSignedValue(b, 2));
assertEquals(0x020100L, dc.getSignedValue(b, 3));
assertEquals(0x0706050403020100L, dc.getSignedValue(b, 8));
assertEquals(0x0302L, dc.getValue(b, 2, 2)); assertEquals(0x0302L, dc.getValue(b, 2, 2));
assertEquals(0x040302L, dc.getValue(b, 2, 3)); assertEquals(0x040302L, dc.getValue(b, 2, 3));
assertEquals(0x0908070605040302L, dc.getValue(b, 2, 8)); assertEquals(0x0908070605040302L, dc.getValue(b, 2, 8));
@ -92,6 +93,14 @@ public class LittleEndianConverterTest extends AbstractGhidraHeadedIntegrationTe
} }
@Test
public void testGetSignedValues() {
assertEquals(Integer.MIN_VALUE, dc.getSignedValue(bytes(0, 00, 00, 0x80), 4));
assertEquals(-0x800000L, dc.getSignedValue(bytes(0, 00, 0x80, 00), 3));
assertEquals(-256, dc.getSignedValue(bytes(0, 0xFF, 00, 00), 2));
}
@Test @Test
public void testPut() { public void testPut() {
byte[] b2 = new byte[12]; byte[] b2 = new byte[12];

View file

@ -15,7 +15,7 @@
*/ */
package ghidra.program.database.code; package ghidra.program.database.code;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import org.junit.*; import org.junit.*;
@ -133,14 +133,6 @@ public class CodeManager64Test extends AbstractGenericTest {
} }
private byte[] bytes(int... v) {
byte[] byteArray = new byte[v.length];
for (int i = 0; i < v.length; i++) {
byteArray[i] = (byte) v[i];
}
return byteArray;
}
private Address addr(long l) { private Address addr(long l) {
return space.getAddress(l); return space.getAddress(l);
} }

View file

@ -638,14 +638,6 @@ public class CodeManagerTest extends AbstractGenericTest {
assertEquals(addr(0x0101), referencesFrom[0].getToAddress()); assertEquals(addr(0x0101), referencesFrom[0].getToAddress());
} }
private byte[] bytes(int... v) {
byte[] byteArray = new byte[v.length];
for (int i = 0; i < v.length; i++) {
byteArray[i] = (byte) v[i];
}
return byteArray;
}
@Test @Test
public void testGetDataAt() throws Exception { public void testGetDataAt() throws Exception {
listing.createData(addr(0x1740), DefaultDataType.dataType, 1); listing.createData(addr(0x1740), DefaultDataType.dataType, 1);

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -36,7 +35,7 @@ class FileByteBlock implements ByteBlock {
FileByteBlock(byte[] b) { FileByteBlock(byte[] b) {
buf = b; buf = b;
converter = new LittleEndianDataConverter(); converter = LittleEndianDataConverter.INSTANCE;
} }
/* (non-Javadoc) /* (non-Javadoc)
@ -153,12 +152,7 @@ class FileByteBlock implements ByteBlock {
public void setBigEndian(boolean bigEndian) { public void setBigEndian(boolean bigEndian) {
if (this.bigEndian != bigEndian) { if (this.bigEndian != bigEndian) {
this.bigEndian = bigEndian; this.bigEndian = bigEndian;
if (bigEndian) { converter = DataConverter.getInstance(bigEndian);
converter = new BigEndianDataConverter();
}
else {
converter = new LittleEndianDataConverter();
}
} }
} }

View file

@ -68,7 +68,7 @@ public class FileByteBlockTest extends AbstractGenericTest {
@Test @Test
public void testGetInt() throws Exception { public void testGetInt() throws Exception {
block.setBigEndian(true); block.setBigEndian(true);
DataConverter conv = new BigEndianDataConverter(); DataConverter conv = BigEndianDataConverter.INSTANCE;
for (int i = 0; i < 20; i++) { for (int i = 0; i < 20; i++) {
byte[] b = new byte[4]; byte[] b = new byte[4];
@ -77,7 +77,7 @@ public class FileByteBlockTest extends AbstractGenericTest {
} }
block.setBigEndian(false); block.setBigEndian(false);
conv = new LittleEndianDataConverter(); conv = LittleEndianDataConverter.INSTANCE;
for (int i = 0; i < 12; i++) { for (int i = 0; i < 12; i++) {
byte[] b = new byte[4]; byte[] b = new byte[4];
System.arraycopy(buf, i + 4, b, 0, b.length); System.arraycopy(buf, i + 4, b, 0, b.length);
@ -89,7 +89,7 @@ public class FileByteBlockTest extends AbstractGenericTest {
@Test @Test
public void testGetLong() throws Exception { public void testGetLong() throws Exception {
block.setBigEndian(true); block.setBigEndian(true);
DataConverter conv = new BigEndianDataConverter(); DataConverter conv = BigEndianDataConverter.INSTANCE;
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
byte[] b = new byte[8]; byte[] b = new byte[8];
@ -104,7 +104,7 @@ public class FileByteBlockTest extends AbstractGenericTest {
} }
block.setBigEndian(false); block.setBigEndian(false);
conv = new LittleEndianDataConverter(); conv = LittleEndianDataConverter.INSTANCE;
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
byte[] b = new byte[8]; byte[] b = new byte[8];
System.arraycopy(buf, i + 8, b, 0, b.length); System.arraycopy(buf, i + 8, b, 0, b.length);
@ -141,7 +141,7 @@ public class FileByteBlockTest extends AbstractGenericTest {
@Test @Test
public void testSetInt() throws Exception { public void testSetInt() throws Exception {
block.setBigEndian(true); block.setBigEndian(true);
DataConverter conv = new BigEndianDataConverter(); DataConverter conv = BigEndianDataConverter.INSTANCE;
byte[] b = new byte[4]; byte[] b = new byte[4];
System.arraycopy(buf, 35, b, 0, b.length); System.arraycopy(buf, 35, b, 0, b.length);
@ -158,7 +158,7 @@ public class FileByteBlockTest extends AbstractGenericTest {
} }
block.setBigEndian(false); block.setBigEndian(false);
conv = new LittleEndianDataConverter(); conv = LittleEndianDataConverter.INSTANCE;
b = new byte[4]; b = new byte[4];
System.arraycopy(buf, 35, b, 0, b.length); System.arraycopy(buf, 35, b, 0, b.length);
@ -179,7 +179,7 @@ public class FileByteBlockTest extends AbstractGenericTest {
@Test @Test
public void testSetLong() throws Exception { public void testSetLong() throws Exception {
block.setBigEndian(true); block.setBigEndian(true);
DataConverter conv = new BigEndianDataConverter(); DataConverter conv = BigEndianDataConverter.INSTANCE;
byte[] b = new byte[8]; byte[] b = new byte[8];
System.arraycopy(buf, 35, b, 0, b.length); System.arraycopy(buf, 35, b, 0, b.length);
@ -196,7 +196,7 @@ public class FileByteBlockTest extends AbstractGenericTest {
} }
block.setBigEndian(false); block.setBigEndian(false);
conv = new LittleEndianDataConverter(); conv = LittleEndianDataConverter.INSTANCE;
b = new byte[8]; b = new byte[8];
System.arraycopy(buf, 35, b, 0, b.length); System.arraycopy(buf, 35, b, 0, b.length);

View file

@ -395,9 +395,7 @@ public class MachoProcessBindScript extends GhidraScript {
long offset = symbol.getAddress().getOffset(); long offset = symbol.getAddress().getOffset();
DataConverter converter = currentProgram.getLanguage().isBigEndian() ? DataConverter converter = DataConverter.getInstance(currentProgram.getLanguage().isBigEndian());
new BigEndianDataConverter() :
new LittleEndianDataConverter();
if ( currentProgram.getDefaultPointerSize() == 8 ) { if ( currentProgram.getDefaultPointerSize() == 8 ) {
setBytes( getAddress(), converter.getBytes( offset ) ); setBytes( getAddress(), converter.getBytes( offset ) );

View file

@ -32,7 +32,7 @@ public abstract class NSObject implements StructConverter {
/** /**
* All data is stored BIG ENDIAN in a binary plist. * All data is stored BIG ENDIAN in a binary plist.
*/ */
protected DataConverter converter = new BigEndianDataConverter( ); protected DataConverter converter = BigEndianDataConverter.INSTANCE;
public abstract String getType(); public abstract String getType();

View file

@ -28,7 +28,7 @@ import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
public class FixupMacho32bitArmOffsets { public class FixupMacho32bitArmOffsets {
private DataConverter converter = new LittleEndianDataConverter(); private DataConverter converter = LittleEndianDataConverter.INSTANCE;
public InputStream fix(GFile file, long offsetAdjustment, ByteProvider provider, public InputStream fix(GFile file, long offsetAdjustment, ByteProvider provider,
TaskMonitor monitor) throws IOException, MachException { TaskMonitor monitor) throws IOException, MachException {

View file

@ -167,7 +167,7 @@ public class ItemSerializer {
inputStream.skip(MAGIC_NUMBER_POS); inputStream.skip(MAGIC_NUMBER_POS);
byte[] magicBytes = new byte[MAGIC_NUMBER_SIZE]; byte[] magicBytes = new byte[MAGIC_NUMBER_SIZE];
inputStream.read(magicBytes); inputStream.read(magicBytes);
BigEndianDataConverter dc = new BigEndianDataConverter(); BigEndianDataConverter dc = BigEndianDataConverter.INSTANCE;
long magic = dc.getLong(magicBytes); long magic = dc.getLong(magicBytes);
return (magic == MAGIC_NUMBER); return (magic == MAGIC_NUMBER);
} }

View file

@ -325,6 +325,21 @@ public abstract class AbstractGTest {
return testName.getMethodName(); return testName.getMethodName();
} }
/**
* Friendly way to create an array of bytes with static values.
*
* @param unsignedBytes var-args list of unsigned byte values (ie. 0..255)
* @return array of bytes
*/
public static byte[] bytes(int... unsignedBytes) {
byte[] result = new byte[unsignedBytes.length];
for (int i = 0; i < unsignedBytes.length; i++) {
result[i] = (byte) unsignedBytes[i];
}
return result;
}
//================================================================================================== //==================================================================================================
// Wait Methods // Wait Methods
//================================================================================================== //==================================================================================================

View file

@ -16,6 +16,7 @@
package ghidra.util; package ghidra.util;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.Objects;
/** /**
* Helper class to convert a byte array to Java primitives and primitives to a * Helper class to convert a byte array to Java primitives and primitives to a
@ -27,42 +28,26 @@ import java.math.BigInteger;
public class BigEndianDataConverter implements DataConverter { public class BigEndianDataConverter implements DataConverter {
public static final BigEndianDataConverter INSTANCE = new BigEndianDataConverter(); public static final BigEndianDataConverter INSTANCE = new BigEndianDataConverter();
/**
*
*/
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* Constructor for BigEndianDataConverter. * Don't use this constructor to create new instances of this class. Use the static {@link #INSTANCE} instead.
*/ */
public BigEndianDataConverter() { public BigEndianDataConverter() {
// empty
} }
/** @Override
* @see DataConverter#getShort(byte[])
*/
public final short getShort(byte[] b) {
return getShort(b, 0);
}
/**
* @see DataConverter#getShort(byte[], int)
*/
public short getShort(byte[] b, int offset) { public short getShort(byte[] b, int offset) {
Objects.checkFromIndexSize(offset, Short.BYTES, b.length);
return (short) (((b[offset] & 0xff) << 8) | (b[offset + 1] & 0xff)); return (short) (((b[offset] & 0xff) << 8) | (b[offset + 1] & 0xff));
} }
/** @Override
* @see DataConverter#getInt(byte[])
*/
public final int getInt(byte[] b) {
return getInt(b, 0);
}
/**
* @see DataConverter#getInt(byte[], int)
*/
public int getInt(byte[] b, int offset) { public int getInt(byte[] b, int offset) {
Objects.checkFromIndexSize(offset, Integer.BYTES, b.length);
int v = b[offset]; int v = b[offset];
for (int i = 1; i < 4; i++) { for (int i = 1; i < 4; i++) {
v = (v << 8) | (b[offset + i] & 0xff); v = (v << 8) | (b[offset + i] & 0xff);
@ -70,17 +55,10 @@ public class BigEndianDataConverter implements DataConverter {
return v; return v;
} }
/** @Override
* @see DataConverter#getLong(byte[])
*/
public final long getLong(byte[] b) {
return getLong(b, 0);
}
/**
* @see DataConverter#getLong(byte[], int)
*/
public long getLong(byte[] b, int offset) { public long getLong(byte[] b, int offset) {
Objects.checkFromIndexSize(offset, Long.BYTES, b.length);
long v = b[offset]; long v = b[offset];
for (int i = 1; i < 8; i++) { for (int i = 1; i < 8; i++) {
v = (v << 8) | (b[offset + i] & 0xff); v = (v << 8) | (b[offset + i] & 0xff);
@ -88,20 +66,11 @@ public class BigEndianDataConverter implements DataConverter {
return v; return v;
} }
/** @Override
* @see ghidra.util.DataConverter#getValue(byte[], int)
*/
public long getValue(byte[] b, int size) {
return getValue(b, 0, size);
}
/**
* @see ghidra.util.DataConverter#getValue(byte[], int, int)
*/
public long getValue(byte[] b, int offset, int size) { public long getValue(byte[] b, int offset, int size) {
if (size > 8) { Objects.checkFromIndexSize(offset, size, b.length);
throw new IndexOutOfBoundsException("size exceeds sizeof long: " + size); Objects.checkIndex(size, Long.BYTES + 1);
}
long val = 0; long val = 0;
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
val = (val << 8) | (b[offset + i] & 0xff); val = (val << 8) | (b[offset + i] & 0xff);
@ -109,16 +78,10 @@ public class BigEndianDataConverter implements DataConverter {
return val; return val;
} }
@Override
public final BigInteger getBigInteger(byte[] b, int size, boolean signed) {
return getBigInteger(b, 0, size, signed);
}
@Override @Override
public final BigInteger getBigInteger(byte[] b, int offset, int size, boolean signed) { public final BigInteger getBigInteger(byte[] b, int offset, int size, boolean signed) {
if ((size + offset) > b.length) { Objects.checkFromIndexSize(offset, size, b.length);
throw new IndexOutOfBoundsException("insufficient bytes");
}
if (offset != 0 || size != b.length) { if (offset != 0 || size != b.length) {
int index = 0; int index = 0;
if (!signed && b[offset] < 0) { if (!signed && b[offset] < 0) {
@ -132,39 +95,25 @@ public class BigEndianDataConverter implements DataConverter {
} }
else if (!signed && b[0] < 0) { else if (!signed && b[0] < 0) {
// keep unsigned - prepend 0 byte // keep unsigned - prepend 0 byte
byte[] bytes = new byte[size+1]; byte[] bytes = new byte[size + 1];
System.arraycopy(b, 0, bytes, 1, size); System.arraycopy(b, 0, bytes, 1, size);
b = bytes; b = bytes;
} }
return new BigInteger(b); return new BigInteger(b);
} }
/** @Override
* @see DataConverter#getBytes(short, byte[]) public void putShort(byte[] b, int offset, short value) {
*/ Objects.checkFromIndexSize(offset, Short.BYTES, b.length);
public final void getBytes(short value, byte[] b) {
getBytes(value, b, 0);
}
/**
* @see DataConverter#getBytes(short, byte[], int)
*/
public void getBytes(short value, byte[] b, int offset) {
b[offset] = (byte) (value >> 8); b[offset] = (byte) (value >> 8);
b[offset + 1] = (byte) (value & 0xff); b[offset + 1] = (byte) (value & 0xff);
} }
/** @Override
* @see DataConverter#getBytes(int, byte[]) public void putInt(byte[] b, int offset, int value) {
*/ Objects.checkFromIndexSize(offset, Integer.BYTES, b.length);
public final void getBytes(int value, byte[] b) {
getBytes(value, b, 0);
}
/**
* @see DataConverter#getBytes(int, byte[], int)
*/
public void getBytes(int value, byte[] b, int offset) {
b[offset + 3] = (byte) (value); b[offset + 3] = (byte) (value);
for (int i = 2; i >= 0; i--) { for (int i = 2; i >= 0; i--) {
value >>= 8; value >>= 8;
@ -172,113 +121,20 @@ public class BigEndianDataConverter implements DataConverter {
} }
} }
/** @Override
* @see DataConverter#getBytes(long, byte[]) public void putValue(long value, int size, byte[] b, int offset) {
*/ Objects.checkFromIndexSize(offset, size, b.length);
public final void getBytes(long value, byte[] b) { Objects.checkIndex(size, Long.BYTES + 1);
getBytes(value, 8, b, 0);
}
/**
* @see DataConverter#getBytes(long, byte[], int)
*/
public void getBytes(long value, byte[] b, int offset) {
getBytes(value, 8, b, offset);
}
/**
* @see ghidra.util.DataConverter#getBytes(long, int, byte[], int)
*/
public void getBytes(long value, int size, byte[] b, int offset) {
for (int i = size - 1; i >= 0; i--) { for (int i = size - 1; i >= 0; i--) {
b[offset + i] = (byte) value; b[offset + i] = (byte) value;
value >>= 8; value >>= 8;
} }
} }
/**
* @see ghidra.util.DataConverter#putInt(byte[], int, int)
*/
public final void putInt(byte[] b, int offset, int value) {
getBytes(value, b, offset);
}
/**
* @see ghidra.util.DataConverter#putInt(byte[], int)
*/
public final void putInt(byte[] b, int value) {
getBytes(value, b);
}
/**
* @see ghidra.util.DataConverter#putLong(byte[], int, long)
*/
public final void putLong(byte[] b, int offset, long value) {
getBytes(value, b, offset);
}
/**
* @see ghidra.util.DataConverter#putLong(byte[], long)
*/
public final void putLong(byte[] b, long value) {
getBytes(value, b);
}
/**
* @see ghidra.util.DataConverter#putShort(byte[], int, short)
*/
public final void putShort(byte[] b, int offset, short value) {
getBytes(value, b, offset);
}
/**
* @see ghidra.util.DataConverter#putShort(byte[], short)
*/
public final void putShort(byte[] b, short value) {
getBytes(value, b);
}
/**
* @see ghidra.util.DataConverter#getBytes(int)
*/
public byte[] getBytes(int value) {
byte[] bytes = new byte[4];
getBytes(value, bytes);
return bytes;
}
/**
* @see ghidra.util.DataConverter#getBytes(long)
*/
public byte[] getBytes(long value) {
byte[] bytes = new byte[8];
getBytes(value, bytes);
return bytes;
}
/**
* @see ghidra.util.DataConverter#getBytes(short)
*/
public byte[] getBytes(short value) {
byte[] bytes = new byte[2];
getBytes(value, bytes);
return bytes;
}
@Override
public byte[] getBytes(BigInteger value, int size) {
byte[] bytes = new byte[size];
putBigInteger(bytes, 0, size, value);
return bytes;
}
@Override
public void getBytes(BigInteger value, int size, byte[] b, int offset) {
putBigInteger(b, offset, size, value);
}
@Override @Override
public void putBigInteger(byte[] b, int offset, int size, BigInteger value) { public void putBigInteger(byte[] b, int offset, int size, BigInteger value) {
Objects.checkFromIndexSize(offset, size, b.length);
int fillIndex = offset; // start fill from MSB int fillIndex = offset; // start fill from MSB
int srcIndex; int srcIndex;
@ -300,9 +156,4 @@ public class BigEndianDataConverter implements DataConverter {
System.arraycopy(valBytes, srcIndex, b, fillIndex, fillCnt); System.arraycopy(valBytes, srcIndex, b, fillIndex, fillCnt);
} }
@Override
public void putBigInteger(byte[] b, int size, BigInteger value) {
putBigInteger(b, 0, size, value);
}
} }

View file

@ -19,277 +19,492 @@ import java.io.Serializable;
import java.math.BigInteger; import java.math.BigInteger;
/** /**
* * Stateless helper classes with static singleton instances that contain methods to convert
* Defines methods to convert byte arrays to a specific primitive Java types, * Java numeric types to and from their raw form in a byte array.
* and to populate byte arrays from primitive Java types. * <p>
*
* *
*/ */
public interface DataConverter extends Serializable { public interface DataConverter extends Serializable {
/**
* Returns the correct DataConverter static instance for the requested endian-ness.
*
* @param isBigEndian boolean flag, true means big endian
* @return static DataConverter instance
*/
public static DataConverter getInstance(boolean isBigEndian) { public static DataConverter getInstance(boolean isBigEndian) {
return isBigEndian ? BigEndianDataConverter.INSTANCE : LittleEndianDataConverter.INSTANCE; return isBigEndian ? BigEndianDataConverter.INSTANCE : LittleEndianDataConverter.INSTANCE;
} }
/** /**
* Get the short value from the given byte array. * Returns the endianess of this DataConverter instance.
* @param b array containing bytes *
* @throws IndexOutOfBoundsException if byte array size is * @return boolean flag, true means big-endian
* less than 2.
*/ */
public short getShort(byte[] b); default boolean isBigEndian() {
return this instanceof BigEndianDataConverter;
}
/** /**
* Get the short value from the given byte array. * Get the short value from the given byte array.
* @param b array containing bytes * @param b array containing bytes
* @return signed short value from the beginning of the specified array
* @throws IndexOutOfBoundsException if byte array size is less than 2.
*/
default short getShort(byte[] b) {
return getShort(b, 0);
}
/**
* Get the short value from the given byte array.
*
* @param b array containing bytes
* @param offset offset into byte array for getting the short * @param offset offset into byte array for getting the short
* @throws IndexOutOfBoundsException if byte array size is * @return signed short value
* less than offset+2. * @throws IndexOutOfBoundsException if byte array size is less than offset+2
*/ */
public short getShort(byte[] b, int offset); short getShort(byte[] b, int offset);
/** /**
* Get the int value from the given byte array. * Get the int value from the given byte array.
*
* @param b array containing bytes * @param b array containing bytes
* @throws IndexOutOfBoundsException if byte array size is * @return signed int value from the beginning of the specified array
* less than 4. * @throws IndexOutOfBoundsException if byte array size is less than 4
*/ */
public int getInt(byte[] b); default int getInt(byte[] b) {
return getInt(b, 0);
}
/** /**
* Get the int value from the given byte array. * Get the int value from the given byte array.
*
* @param b array containing bytes * @param b array containing bytes
* @param offset offset into byte array for getting the int * @param offset offset into byte array for getting the int
* @throws IndexOutOfBoundsException if byte array size is * @return signed int value
* less than offset+4. * @throws IndexOutOfBoundsException if byte array size is less than offset+4
*/ */
public int getInt(byte[] b, int offset); int getInt(byte[] b, int offset);
/** /**
* Get the long value from the given byte array. * Get the long value from the given byte array.
*
* @param b array containing bytes * @param b array containing bytes
* @throws IndexOutOfBoundsException if byte array size is * @return signed long value from the beginning of the specified array
* less than 8. * @throws IndexOutOfBoundsException if byte array size is less than 8
*/ */
public long getLong(byte[] b); default long getLong(byte[] b) {
return getLong(b, 0);
}
/** /**
* Get the long value from the given byte array. * Get the long value from the given byte array.
*
* @param b array containing bytes * @param b array containing bytes
* @param offset offset into byte array for getting the long * @param offset offset into byte array for getting the long
* @throws IndexOutOfBoundsException if byte array size is * @return signed long value
* less than offset+8. * @throws IndexOutOfBoundsException if byte array size is less than offset+8
*/ */
public long getLong(byte[] b, int offset); long getLong(byte[] b, int offset);
/**
* Get the <b>unsigned</b> value from the given byte array using the specified
* integer size, returned as a long.
* <p>
* Values with a size less than sizeof(long) will <b>not</b> have their sign bit
* extended and therefore will appear as an 'unsigned' value.
* <p>
* Casting the 'unsigned' long value to the correctly sized smaller
* java primitive will cause the value to appear as a signed value.
* <p>
* Values of size 8 (ie. longs) will be signed.
*
* @param b array containing bytes
* @param size number of bytes (1 - 8) to use from array at offset 0
* @return unsigned value from the beginning of the specified array
* @throws IndexOutOfBoundsException if byte array size is less than specified size
*/
default long getValue(byte[] b, int size) {
return getValue(b, 0, size);
}
/**
* Get the <b>unsigned</b> value from the given byte array using the specified
* integer size, returned as a long.
* <p>
* Values with a size less than sizeof(long) will <b>not</b> have their sign bit
* extended and therefore will appear as an 'unsigned' value.
* <p>
* Casting the 'unsigned' long value to the correctly sized smaller
* java primitive will cause the value to appear as a signed value.
* <p>
* Values of size 8 (ie. longs) will be signed.
*
* @param b array containing bytes
* @param size number of bytes (1 - 8) to use from array
* @param offset offset into byte array for getting the long
* @return unsigned value
* @throws IndexOutOfBoundsException if byte array size is
* less than offset+size or size is greater than 8 (sizeof long)
*/
long getValue(byte[] b, int offset, int size);
/**
* Get the <b>signed</b> value from the given byte array using the specified
* integer size, returned as a long.
* <p>
* Values with a size less than sizeof(long) will have their sign bit
* extended.
*
* @param b array containing bytes
* @param size number of bytes (1 - 8) to use from array at offset 0
* @return signed value from the beginning of the specified array
* @throws IndexOutOfBoundsException if byte array size is less than specified size
*/
default long getSignedValue(byte[] b, int size) {
return getSignedValue(b, 0, size);
}
/**
* Get the <b>signed</b> value from the given byte array using the specified
* integer size, returned as a long.
* <p>
* Values with a size less than sizeof(long) will have their sign bit
* extended.
*
* @param b array containing bytes
* @param size number of bytes (1 - 8) to use from array
* @param offset offset into byte array for getting the long
* @return signed value
* @throws IndexOutOfBoundsException if byte array size is
* less than offset+size or size is greater than 8 (sizeof long)
*/
default long getSignedValue(byte[] b, int offset, int size) {
long val = getValue(b, offset, size);
int shiftBits = (8 /*sizeof(long)*/ - size) * 8;
// this little bit of magic will sign-extend the value
val = val << shiftBits;
val = val >> shiftBits;
return val;
}
/** /**
* Get the value from the given byte array using the specified size. * Get the value from the given byte array using the specified size.
*
* @param b array containing bytes * @param b array containing bytes
* @param size number of bytes to use from array at offset 0 * @param size number of bytes to use from array at offset 0
* @param signed boolean flag indicating the value is signed
* @return {@link BigInteger} with value
* @throws IndexOutOfBoundsException if byte array size is * @throws IndexOutOfBoundsException if byte array size is
* less than size. * less than size
*/ */
public long getValue(byte[] b, int size); default BigInteger getBigInteger(byte[] b, int size, boolean signed) {
return getBigInteger(b, 0, size, signed);
}
/** /**
* Get the value from the given byte array using the specified size. * Get the value from the given byte array using the specified size.
*
* @param b array containing bytes * @param b array containing bytes
* @param size number of bytes to use from array * @param size number of bytes to use from array
* @param offset offset into byte array for getting the long * @param offset offset into byte array for getting the long
* @param signed boolean flag indicating the value is signed
* @return {@link BigInteger} with value
* @throws IndexOutOfBoundsException if byte array size is * @throws IndexOutOfBoundsException if byte array size is
* less than offset+size or size is greater than 8 (sizeof long). * less than offset+size
*/ */
public long getValue(byte[] b, int offset, int size); BigInteger getBigInteger(byte[] b, int offset, int size, boolean signed);
//-------------------------------------------------------------------------------
/** /**
* Get the value from the given byte array using the specified size. * Converts the short value to an array of bytes.
* @param b array containing bytes *
* @param size number of bytes to use from array at offset 0 * @param value short value to be converted
* @throws IndexOutOfBoundsException if byte array size is * @return array of bytes
* less than size.
*/ */
public BigInteger getBigInteger(byte[] b, int size, boolean signed); default byte[] getBytes(short value) {
byte[] bytes = new byte[2];
getBytes(value, bytes);
return bytes;
}
/** /**
* Get the value from the given byte array using the specified size. * Converts the int value to an array of bytes.
* @param b array containing bytes *
* @param size number of bytes to use from array * @param value int value to be converted
* @param offset offset into byte array for getting the long * @return array of bytes
* @throws IndexOutOfBoundsException if byte array size is
* less than offset+size.
*/ */
public BigInteger getBigInteger(byte[] b, int offset, int size, boolean signed); default byte[] getBytes(int value) {
byte[] bytes = new byte[4];
getBytes(value, bytes);
return bytes;
}
/**
* Converts the long value to an array of bytes.
*
* @param value long value to be converted
* @return array of bytes
*/
default byte[] getBytes(long value) {
byte[] bytes = new byte[8];
getBytes(value, bytes);
return bytes;
}
/**
* Converts the value to an array of bytes.
*
* @param value value to be converted
* @param size value size in bytes
* @return array of bytes
*/
default byte[] getBytes(BigInteger value, int size) {
byte[] bytes = new byte[size];
putBigInteger(bytes, 0, size, value);
return bytes;
}
//-------------------------------------------------------------------------------
/**
* Writes a short value into a byte array.
*
* @param b array to contain the bytes
* @param value the short value
* @throws IndexOutOfBoundsException if byte array is too small to hold the value
*/
default void putShort(byte[] b, short value) {
putShort(b, 0, value);
}
/**
* Writes a short value into the byte array at the given offset
*
* @param b array to contain the bytes
* @param offset the offset into the byte array to store the value
* @param value the short value
* @throws IndexOutOfBoundsException if offset is too large or byte array
* is too small to hold the value
*/
void putShort(byte[] b, int offset, short value);
/**
* Writes a int value into a byte array.
* <p>
* See {@link #getBytes(int, byte[])}
*
* @param b array to contain the bytes
* @param value the int value
* @throws IndexOutOfBoundsException if byte array is too small to hold the value
*/
default void putInt(byte[] b, int value) {
putInt(b, 0, value);
}
/**
* Writes a int value into the byte array at the given offset.
* <p>
* See {@link #getBytes(int, byte[], int)}
*
* @param b array to contain the bytes
* @param offset the offset into the byte array to store the value
* @param value the int value
* @throws IndexOutOfBoundsException if offset is too large or byte array
* is too small to hold the value
*/
void putInt(byte[] b, int offset, int value);
/**
* Writes a long value into a byte array.
* <p>
* See {@link #getBytes(long, byte[])}
*
* @param b array to contain the bytes
* @param value the long value
* @throws IndexOutOfBoundsException if byte array is too small to hold the value
*/
default void putLong(byte[] b, long value) {
putLong(b, 0, value);
}
/**
* Writes a long value into the byte array at the given offset
* <p>
* See {@link #getBytes(long, byte[], int)}
*
* @param b array to contain the bytes
* @param offset the offset into the byte array to store the value
* @param value the long value
* @throws IndexOutOfBoundsException if offset is too large or byte array
* is too small to hold the value
*/
default void putLong(byte[] b, int offset, long value) {
putValue(value, Long.BYTES, b, offset);
}
/**
* Converts the given value to bytes using the number of least significant bytes
* specified by size.
* <p>
*
* @param value value to convert to bytes
* @param size number of least significant bytes of value to be written to the byte array
* @param b byte array to store bytes
* @param offset offset into byte array to put the bytes
* @throws IndexOutOfBoundsException if (offset+size)&gt;b.length
*/
void putValue(long value, int size, byte[] b, int offset);
/**
* Writes a value of specified size into the byte array at the given offset.
* <p>
* See {@link #getBytes(BigInteger, int, byte[], int)}
*
* @param b array to contain the bytes at offset 0
* @param size number of bytes to be written
* @param value BigInteger value to convert
* @throws IndexOutOfBoundsException if byte array is less than specified size
*/
default void putBigInteger(byte[] b, int size, BigInteger value) {
putBigInteger(b, 0, size, value);
}
/**
* Writes a value of specified size into the byte array at the given offset
* <p>
* See {@link #getBytes(BigInteger, int, byte[], int)}
*
* @param b array to contain the bytes
* @param offset the offset into the byte array to store the value
* @param size number of bytes to be written
* @param value BigInteger value to convert
* @throws IndexOutOfBoundsException if (offset+size)&gt;b.length
*/
public void putBigInteger(byte[] b, int offset, int size, BigInteger value);
//--------------------------------------------------------------------------------
/** /**
* Converts the given value to bytes. * Converts the given value to bytes.
* See {@link #putShort(byte[], short)}
* @param value value to convert to bytes * @param value value to convert to bytes
* @param b byte array to store bytes * @param b byte array to store bytes
* @throws IndexOutOfBoundsException if b.length is not at least * @throws IndexOutOfBoundsException if b.length is not at least
* 2. * 2.
*/ */
public void getBytes(short value, byte[] b); default void getBytes(short value, byte[] b) {
getBytes(value, b, 0);
}
/** /**
* Converts the given value to bytes. * Converts the given value to bytes.
* <p>
* See {@link #putShort(byte[], int, short)}
*
* @param value value to convert to bytes * @param value value to convert to bytes
* @param b byte array to store bytes * @param b byte array to store bytes
* @param offset offset into byte array to put the bytes * @param offset offset into byte array to put the bytes
* @throws IndexOutOfBoundsException if (offset+2)&gt;b.length * @throws IndexOutOfBoundsException if (offset+2)&gt;b.length
*/ */
public void getBytes(short value, byte[] b, int offset); default void getBytes(short value, byte[] b, int offset) {
putShort(b, offset, value);
}
/** /**
* Converts the given value to bytes. * Converts the given value to bytes.
* <p>
* See {@link #putInt(byte[], int)}
*
* @param value value to convert to bytes * @param value value to convert to bytes
* @param b byte array to store bytes * @param b byte array to store bytes
* @throws IndexOutOfBoundsException if b.length is not at least * @throws IndexOutOfBoundsException if b.length is not at least
* 4. * 4.
*/ */
public void getBytes(int value, byte[] b); default void getBytes(int value, byte[] b) {
getBytes(value, b, 0);
}
/** /**
* Converts the given value to bytes. * Converts the given value to bytes.
* <p>
* See {@link #putInt(byte[], int)}
*
* @param value value to convert to bytes * @param value value to convert to bytes
* @param b byte array to store bytes * @param b byte array to store bytes
* @param offset offset into byte array to put the bytes * @param offset offset into byte array to put the bytes
* @throws IndexOutOfBoundsException if (offset+4)&gt;b.length * @throws IndexOutOfBoundsException if (offset+4)&gt;b.length
*/ */
public void getBytes(int value, byte[] b, int offset); default void getBytes(int value, byte[] b, int offset) {
putInt(b, offset, value);
}
/** /**
* Converts the given value to bytes. * Converts the given value to bytes.
* <p>
* See {@link #putLong(byte[], long)}
*
* @param value value to convert to bytes * @param value value to convert to bytes
* @param b byte array to store bytes * @param b byte array to store bytes
* @throws IndexOutOfBoundsException if b.length is not at least * @throws IndexOutOfBoundsException if b.length is not at least
* 8. * 8.
*/ */
public void getBytes(long value, byte[] b); default void getBytes(long value, byte[] b) {
getBytes(value, b, 0);
}
/** /**
* Converts the given value to bytes. * Converts the given value to bytes.
* <p>
* See {@link #putLong(byte[], long)}
*
* @param value value to convert to bytes * @param value value to convert to bytes
* @param b byte array to store bytes * @param b byte array to store bytes
* @param offset offset into byte array to put the bytes * @param offset offset into byte array to put the bytes
* @throws IndexOutOfBoundsException if (offset+8)&gt;b.length * @throws IndexOutOfBoundsException if (offset+8)&gt;b.length
*/ */
public void getBytes(long value, byte[] b, int offset); default void getBytes(long value, byte[] b, int offset) {
putLong(b, offset, value);
}
/** /**
* Converts the given value to bytes using the number of least significant bytes * Converts the given value to bytes using the number of least significant bytes
* specified by size. * specified by size.
* <p>
* See {@link #putValue(long, int, byte[], int)}
*
* @param value value to convert to bytes
* @param size number of least significant bytes of value to be written to the byte array
* @param b byte array to store bytes
* @param offset offset into byte array to put the bytes
* @throws IndexOutOfBoundsException if (offset+size)&gt;b.length
*/
default void getBytes(long value, int size, byte[] b, int offset) {
putValue(value, size, b, offset);
}
/**
* Converts the given value to bytes using the number of least significant bytes
* specified by size.
* <p>
* See {@link #putBigInteger(byte[], int, BigInteger)}
*
* @param value value to convert to bytes * @param value value to convert to bytes
* @param size number of least significant bytes of value to be written to the byte array * @param size number of least significant bytes of value to be written to the byte array
* @param b byte array to store bytes * @param b byte array to store bytes
* @param offset offset into byte array to put the bytes * @param offset offset into byte array to put the bytes
* @throws IndexOutOfBoundsException if (offset+size)&gt;b.length. * @throws IndexOutOfBoundsException if (offset+size)&gt;b.length.
*/ */
public void getBytes(long value, int size, byte[] b, int offset); default void getBytes(BigInteger value, int size, byte[] b, int offset) {
putBigInteger(b, offset, size, value);
/** }
* Converts the given value to bytes using the number of least significant bytes
* specified by size.
* @param value value to convert to bytes
* @param size number of least significant bytes of value to be written to the byte array
* @param b byte array to store bytes
* @param offset offset into byte array to put the bytes
* @throws IndexOutOfBoundsException if (offset+size)&gt;b.length.
*/
public void getBytes(BigInteger value, int size, byte[] b, int offset);
/**
* Converts the short value to an array of bytes.
* @param value short value to be converted
* @return array of bytes
*/
public byte[] getBytes(short value);
/**
* Converts the int value to an array of bytes.
* @param value int value to be converted
* @return array of bytes
*/
public byte[] getBytes(int value);
/**
* Converts the long value to an array of bytes.
* @param value long value to be converted
* @return array of bytes
*/
public byte[] getBytes(long value);
/**
* Converts the value to an array of bytes.
* @param value value to be converted
* @param size value size in bytes
* @return array of bytes
*/
public byte[] getBytes(BigInteger value, int size);
/**
* Writes a short value into a byte array.
* @param b array to contain the bytes;
* @param value the short value
*/
public void putShort(byte[] b, short value);
/**
* Writes a short value into the byte array at the given offset
* @param b array to contain the bytes;
* @param offset the offset into the byte array to store the value.
* @param value the short value
*/
public void putShort(byte[] b, int offset, short value);
/**
* Writes a int value into a byte array.
* @param b array to contain the bytes;
* @param value the int value
*/
public void putInt(byte[] b, int value);
/**
* Writes a int value into the byte array at the given offset
* @param b array to contain the bytes;
* @param offset the offset into the byte array to store the value.
* @param value the int value
*/
public void putInt(byte[] b, int offset, int value);
/**
* Writes a long value into a byte array.
* @param b array to contain the bytes;
* @param value the long value
*/
public void putLong(byte[] b, long value);
/**
* Writes a long value into the byte array at the given offset
* @param b array to contain the bytes;
* @param offset the offset into the byte array to store the value.
* @param value the long value
*/
public void putLong(byte[] b, int offset, long value);
/**
* Writes a value of specified size into the byte array at the given offset
* @param b array to contain the bytes at offset 0;
* @param size number of bytes to be written
* @param value
*/
public void putBigInteger(byte[] b, int size, BigInteger value);
/**
* Writes a value of specified size into the byte array at the given offset
* @param b array to contain the bytes;
* @param offset the offset into the byte array to store the value.
* @param size number of bytes to be written
* @param value
*/
public void putBigInteger(byte[] b, int offset, int size, BigInteger value);
/** /**
* Swap the least-significant bytes (based upon size) * Swap the least-significant bytes (based upon size)
* @param val value whoose bytes are to be swapped * @param val value whose bytes are to be swapped
* @param size number of least significant bytes to be swapped * @param size number of least significant bytes to be swapped
* @return value with bytes swapped (any high-order bytes beyond size will be 0) * @return value with bytes swapped (any high-order bytes beyond size will be 0)
*/ */

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,6 +16,7 @@
package ghidra.util; package ghidra.util;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.Objects;
/** /**
* *
@ -25,43 +25,29 @@ import java.math.BigInteger;
*/ */
public class LittleEndianDataConverter implements DataConverter { public class LittleEndianDataConverter implements DataConverter {
public static LittleEndianDataConverter INSTANCE = new LittleEndianDataConverter(); public static final LittleEndianDataConverter INSTANCE = new LittleEndianDataConverter();
/**
*
*/
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* Constructor for BigEndianDataConverter. * Don't use this constructor to create new instances of this class. Use the static {@link #INSTANCE} instead
* or {@link DataConverter#getInstance(Endian)}
*/ */
public LittleEndianDataConverter() { public LittleEndianDataConverter() {
// empty
} }
/** @Override
* @see DataConverter#getShort(byte[])
*/
public final short getShort(byte[] b) {
return getShort(b, 0);
}
/**
* @see DataConverter#getShort(byte[], int)
*/
public short getShort(byte[] b, int offset) { public short getShort(byte[] b, int offset) {
Objects.checkFromIndexSize(offset, Short.BYTES, b.length);
return (short) (((b[offset + 1] & 0xff) << 8) | (b[offset] & 0xff)); return (short) (((b[offset + 1] & 0xff) << 8) | (b[offset] & 0xff));
} }
/** @Override
* @see DataConverter#getInt(byte[])
*/
public final int getInt(byte[] b) {
return getInt(b, 0);
}
/**
* @see DataConverter#getInt(byte[], int)
*/
public int getInt(byte[] b, int offset) { public int getInt(byte[] b, int offset) {
Objects.checkFromIndexSize(offset, Integer.BYTES, b.length);
int v = b[offset + 3]; int v = b[offset + 3];
for (int i = 2; i >= 0; i--) { for (int i = 2; i >= 0; i--) {
v = (v << 8) | (b[offset + i] & 0xff); v = (v << 8) | (b[offset + i] & 0xff);
@ -69,17 +55,10 @@ public class LittleEndianDataConverter implements DataConverter {
return v; return v;
} }
/** @Override
* @see DataConverter#getLong(byte[])
*/
public final long getLong(byte[] b) {
return getLong(b, 0);
}
/**
* @see DataConverter#getLong(byte[], int)
*/
public long getLong(byte[] b, int offset) { public long getLong(byte[] b, int offset) {
Objects.checkFromIndexSize(offset, Long.BYTES, b.length);
long v = b[offset + 7]; long v = b[offset + 7];
for (int i = 6; i >= 0; i--) { for (int i = 6; i >= 0; i--) {
v = (v << 8) | (b[offset + i] & 0xff); v = (v << 8) | (b[offset + i] & 0xff);
@ -87,20 +66,11 @@ public class LittleEndianDataConverter implements DataConverter {
return v; return v;
} }
/** @Override
* @see ghidra.util.DataConverter#getValue(byte[], int)
*/
public long getValue(byte[] b, int size) {
return getValue(b, 0, size);
}
/**
* @see ghidra.util.DataConverter#getValue(byte[], int, int)
*/
public long getValue(byte[] b, int offset, int size) { public long getValue(byte[] b, int offset, int size) {
if (size > 8) { Objects.checkFromIndexSize(offset, size, b.length);
throw new IndexOutOfBoundsException("size exceeds sizeof long: " + size); Objects.checkIndex(size, Long.BYTES + 1);
}
long val = 0; long val = 0;
for (int i = size - 1; i >= 0; i--) { for (int i = size - 1; i >= 0; i--) {
val = (val << 8) | (b[offset + i] & 0xff); val = (val << 8) | (b[offset + i] & 0xff);
@ -109,15 +79,9 @@ public class LittleEndianDataConverter implements DataConverter {
} }
@Override @Override
public final BigInteger getBigInteger(byte[] b, int size, boolean signed) { public BigInteger getBigInteger(byte[] b, int offset, int size, boolean signed) {
return getBigInteger(b, 0, size, signed); Objects.checkFromIndexSize(offset, size, b.length);
}
@Override
public final BigInteger getBigInteger(byte[] b, int offset, int size, boolean signed) {
if ((size + offset) > b.length) {
throw new IndexOutOfBoundsException("insufficient bytes");
}
int msbIndex = 0; int msbIndex = 0;
if (!signed) { if (!signed) {
// prepend 0 byte // prepend 0 byte
@ -132,32 +96,18 @@ public class LittleEndianDataConverter implements DataConverter {
return new BigInteger(bytes); return new BigInteger(bytes);
} }
/** @Override
* @see DataConverter#getBytes(short, byte[]) public void putShort(byte[] b, int offset, short value) {
*/ Objects.checkFromIndexSize(offset, Short.BYTES, b.length);
public final void getBytes(short value, byte[] b) {
getBytes(value, b, 0);
}
/**
* @see DataConverter#getBytes(short, byte[], int)
*/
public void getBytes(short value, byte[] b, int offset) {
b[offset + 1] = (byte) (value >> 8); b[offset + 1] = (byte) (value >> 8);
b[offset] = (byte) (value & 0xff); b[offset] = (byte) (value & 0xff);
} }
/** @Override
* @see DataConverter#getBytes(int, byte[]) public void putInt(byte[] b, int offset, int value) {
*/ Objects.checkFromIndexSize(offset, Integer.BYTES, b.length);
public final void getBytes(int value, byte[] b) {
getBytes(value, b, 0);
}
/**
* @see DataConverter#getBytes(int, byte[], int)
*/
public void getBytes(int value, byte[] b, int offset) {
b[offset] = (byte) (value); b[offset] = (byte) (value);
for (int i = 1; i < 4; i++) { for (int i = 1; i < 4; i++) {
value >>= 8; value >>= 8;
@ -165,113 +115,20 @@ public class LittleEndianDataConverter implements DataConverter {
} }
} }
/** @Override
* @see DataConverter#getBytes(long, byte[]) public void putValue(long value, int size, byte[] b, int offset) {
*/ Objects.checkFromIndexSize(offset, size, b.length);
public final void getBytes(long value, byte[] b) { Objects.checkIndex(size, Long.BYTES + 1);
getBytes(value, 8, b, 0);
}
/**
* @see DataConverter#getBytes(long, byte[], int)
*/
public void getBytes(long value, byte[] b, int offset) {
getBytes(value, 8, b, offset);
}
/**
* @see ghidra.util.DataConverter#getBytes(long, int, byte[], int)
*/
public void getBytes(long value, int size, byte[] b, int offset) {
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
b[offset + i] = (byte) value; b[offset + i] = (byte) value;
value >>= 8; value >>= 8;
} }
} }
/**
* @see ghidra.util.DataConverter#putInt(byte[], int, int)
*/
public final void putInt(byte[] b, int offset, int value) {
getBytes(value, b, offset);
}
/**
* @see ghidra.util.DataConverter#putInt(byte[], int)
*/
public final void putInt(byte[] b, int value) {
getBytes(value, b);
}
/**
* @see ghidra.util.DataConverter#putLong(byte[], int, long)
*/
public final void putLong(byte[] b, int offset, long value) {
getBytes(value, b, offset);
}
/**
* @see ghidra.util.DataConverter#putLong(byte[], long)
*/
public final void putLong(byte[] b, long value) {
getBytes(value, b);
}
/**
* @see ghidra.util.DataConverter#putShort(byte[], int, short)
*/
public final void putShort(byte[] b, int offset, short value) {
getBytes(value, b, offset);
}
/**
* @see ghidra.util.DataConverter#putShort(byte[], short)
*/
public final void putShort(byte[] b, short value) {
getBytes(value, b);
}
/**
* @see ghidra.util.DataConverter#getBytes(int)
*/
public byte[] getBytes(int value) {
byte[] bytes = new byte[4];
getBytes(value, bytes);
return bytes;
}
/**
* @see ghidra.util.DataConverter#getBytes(long)
*/
public byte[] getBytes(long value) {
byte[] bytes = new byte[8];
getBytes(value, bytes);
return bytes;
}
/**
* @see ghidra.util.DataConverter#getBytes(short)
*/
public byte[] getBytes(short value) {
byte[] bytes = new byte[2];
getBytes(value, bytes);
return bytes;
}
@Override
public byte[] getBytes(BigInteger value, int size) {
byte[] bytes = new byte[size];
putBigInteger(bytes, 0, size, value);
return bytes;
}
@Override
public void getBytes(BigInteger value, int size, byte[] b, int offset) {
putBigInteger(b, offset, size, value);
}
@Override @Override
public void putBigInteger(byte[] b, int offset, int size, BigInteger value) { public void putBigInteger(byte[] b, int offset, int size, BigInteger value) {
Objects.checkFromIndexSize(offset, size, b.length);
int fillIndex = offset + size - 1; // start fill from MSB int fillIndex = offset + size - 1; // start fill from MSB
int srcIndex; int srcIndex;
@ -292,9 +149,4 @@ public class LittleEndianDataConverter implements DataConverter {
} }
} }
@Override
public void putBigInteger(byte[] b, int size, BigInteger value) {
putBigInteger(b, 0, size, value);
}
} }

View file

@ -29,6 +29,7 @@ import util.CollectionUtils;
public final class NumericUtilities { public final class NumericUtilities {
public static final BigInteger MAX_UNSIGNED_LONG = new BigInteger("ffffffffffffffff", 16); public static final BigInteger MAX_UNSIGNED_LONG = new BigInteger("ffffffffffffffff", 16);
public static final BigInteger MAX_SIGNED_LONG = new BigInteger("7fffffffffffffff", 16); public static final BigInteger MAX_SIGNED_LONG = new BigInteger("7fffffffffffffff", 16);
public static final long MAX_UNSIGNED_INT32_AS_LONG = 0xffffffffL;
private final static String HEX_PREFIX_X = "0X"; private final static String HEX_PREFIX_X = "0X";
private final static String HEX_PREFIX_x = "0x"; private final static String HEX_PREFIX_x = "0x";
@ -228,14 +229,26 @@ public final class NumericUtilities {
return buf.toString(); return buf.toString();
} }
public final static BigInteger unsignedLongToBigInteger(long value) { /**
* Converts a <strong>unsigned</strong> long value, which is currently stored in a
* java <strong>signed</strong> long, into a {@link BigInteger}.
* <p>
* In other words, the full 64 bits of the primitive java <strong>signed</strong>
* long is being used to store an <strong>unsigned</strong> value. This
* method converts this into a positive BigInteger value.
*
* @param value java <strong>unsigned</strong> long value stuffed into a
* java <strong>signed</strong> long
* @return new {@link BigInteger} with the positive value of the unsigned long value
*/
public static BigInteger unsignedLongToBigInteger(long value) {
if (value >= 0) { if (value >= 0) {
return BigInteger.valueOf(value); return BigInteger.valueOf(value);
} }
return MAX_UNSIGNED_LONG.add(BigInteger.valueOf(value + 1)); return MAX_UNSIGNED_LONG.add(BigInteger.valueOf(value + 1));
} }
public final static long bigIntegerToUnsignedLong(BigInteger value) { public static long bigIntegerToUnsignedLong(BigInteger value) {
if (value.compareTo(MAX_SIGNED_LONG) <= 0) { if (value.compareTo(MAX_SIGNED_LONG) <= 0) {
return value.longValue(); return value.longValue();
} }

View file

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

View file

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

View file

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

View file

@ -24,6 +24,7 @@ import ghidra.program.model.address.*;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.mem.*; import ghidra.program.model.mem.*;
import ghidra.program.model.symbol.*; import ghidra.program.model.symbol.*;
import ghidra.util.DataConverter;
/** /**
* Basic implementation for a pointer dataType * Basic implementation for a pointer dataType
@ -287,7 +288,7 @@ public class PointerDataType extends BuiltIn implements Pointer {
@Override @Override
public String getDescription() { public String getDescription() {
StringBuffer sbuf = new StringBuffer(); StringBuilder sbuf = new StringBuilder();
if (length > 0) { if (length > 0) {
sbuf.append(Integer.toString(8 * length)); sbuf.append(Integer.toString(8 * length));
sbuf.append("-bit "); sbuf.append("-bit ");
@ -342,6 +343,7 @@ public class PointerDataType extends BuiltIn implements Pointer {
if (buf.getAddress() instanceof SegmentedAddress) { if (buf.getAddress() instanceof SegmentedAddress) {
try { try {
// NOTE: conversion assumes a little-endian space
return getSegmentedAddressValue(buf, size); return getSegmentedAddressValue(buf, size);
} }
catch (AddressOutOfBoundsException e) { catch (AddressOutOfBoundsException e) {
@ -362,21 +364,7 @@ public class PointerDataType extends BuiltIn implements Pointer {
return null; return null;
} }
boolean isBigEndian = buf.isBigEndian(); // ENDIAN.isBigEndian(settings, buf); long val = DataConverter.getInstance(buf.isBigEndian()).getValue(bytes, size);
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);
}
try { try {
return targetSpace.getAddress(val, true); return targetSpace.getAddress(val, true);
@ -387,22 +375,27 @@ public class PointerDataType extends BuiltIn implements Pointer {
return null; 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) { private static Address getSegmentedAddressValue(MemBuffer buf, int dataLen) {
SegmentedAddress a = (SegmentedAddress) buf.getAddress(); SegmentedAddress a = (SegmentedAddress) buf.getAddress();
int segment = a.getSegment(); int segment = a.getSegment();
int offset = 0; int offset = 0;
try { try {
switch (dataLen) { switch (dataLen) {
case 1: case 2: // near pointer
offset = buf.getByte(0) & 0xff; offset = (int) buf.getVarLengthUnsignedInt(0, dataLen);
break; break;
case 2: case 4: // far pointer
offset = buf.getShort(0) & 0xffff; segment = buf.getUnsignedShort(0);
break; offset = buf.getUnsignedShort(2);
case 4:
case 8:
segment = buf.getShort(0) & 0xffff;
offset = buf.getShort(2) & 0xffff;
break; break;
default: default:
return null; return null;

View file

@ -20,6 +20,7 @@ import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.lang.ProcessorContext; import ghidra.program.model.lang.ProcessorContext;
import ghidra.program.model.mem.MemBuffer; import ghidra.program.model.mem.MemBuffer;
import ghidra.util.DataConverter;
import ghidra.util.classfinder.ClassTranslator; import ghidra.util.classfinder.ClassTranslator;
/** /**
@ -105,21 +106,7 @@ public class ShiftedAddressDataType extends BuiltIn {
return null; return null;
} }
boolean isBigEndian = buf.isBigEndian(); // ENDIAN.isBigEndian(settings, buf); long val = DataConverter.getInstance(buf.isBigEndian()).getValue(bytes, size);
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);
}
val = val << shift; val = val << shift;

View file

@ -18,8 +18,7 @@ package ghidra.program.model.mem;
import java.math.BigInteger; import java.math.BigInteger;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.util.GhidraBigEndianDataConverter; import ghidra.util.GhidraDataConverter;
import ghidra.util.GhidraLittleEndianDataConverter;
/** /**
* Simple byte buffer implementation of the memBuffer. Since there is no * Simple byte buffer implementation of the memBuffer. Since there is no
@ -29,9 +28,9 @@ import ghidra.util.GhidraLittleEndianDataConverter;
*/ */
public class ByteMemBufferImpl implements MemBuffer { public class ByteMemBufferImpl implements MemBuffer {
private final GhidraDataConverter converter;
private byte[] bytes; private byte[] bytes;
private Address addr; private Address addr;
private final boolean isBigEndian;
/** /**
* Construct a ByteMemBufferImpl object * Construct a ByteMemBufferImpl object
@ -42,23 +41,7 @@ public class ByteMemBufferImpl implements MemBuffer {
public ByteMemBufferImpl(Address addr, byte[] bytes, boolean isBigEndian) { public ByteMemBufferImpl(Address addr, byte[] bytes, boolean isBigEndian) {
this.addr = addr; this.addr = addr;
this.bytes = bytes; this.bytes = bytes;
this.isBigEndian = isBigEndian; this.converter = GhidraDataConverter.getInstance(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];
}
} }
/** /**
@ -96,42 +79,30 @@ public class ByteMemBufferImpl implements MemBuffer {
System.arraycopy(bytes, offset, b, 0, len); System.arraycopy(bytes, offset, b, 0, len);
return len; return len;
} }
@Override @Override
public boolean isBigEndian() { public boolean isBigEndian() {
return isBigEndian; return converter.isBigEndian();
} }
@Override @Override
public short getShort(int offset) throws MemoryAccessException { public short getShort(int offset) throws MemoryAccessException {
if (isBigEndian) { return converter.getShort(this, offset);
return GhidraBigEndianDataConverter.INSTANCE.getShort(this, offset);
}
return GhidraLittleEndianDataConverter.INSTANCE.getShort(this, offset);
} }
@Override @Override
public int getInt(int offset) throws MemoryAccessException { public int getInt(int offset) throws MemoryAccessException {
if (isBigEndian) { return converter.getInt(this, offset);
return GhidraBigEndianDataConverter.INSTANCE.getInt(this, offset);
}
return GhidraLittleEndianDataConverter.INSTANCE.getInt(this, offset);
} }
@Override @Override
public long getLong(int offset) throws MemoryAccessException { public long getLong(int offset) throws MemoryAccessException {
if (isBigEndian) { return converter.getLong(this, offset);
return GhidraBigEndianDataConverter.INSTANCE.getLong(this, offset);
}
return GhidraLittleEndianDataConverter.INSTANCE.getLong(this, offset);
} }
@Override @Override
public BigInteger getBigInteger(int offset, int size, boolean signed) public BigInteger getBigInteger(int offset, int size, boolean signed)
throws MemoryAccessException { throws MemoryAccessException {
if (isBigEndian) { return converter.getBigInteger(this, offset, size, signed);
return GhidraBigEndianDataConverter.INSTANCE.getBigInteger(this, offset, size, signed);
}
return GhidraLittleEndianDataConverter.INSTANCE.getBigInteger(this, offset, size, signed);
} }
} }

View file

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

View file

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

View file

@ -26,12 +26,8 @@ import ghidra.program.model.mem.ByteMemBufferImpl;
public class ArrayStringableTest extends AbstractGTest { public class ArrayStringableTest extends AbstractGTest {
private ByteMemBufferImpl mb(boolean isBE, int... values) { 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); 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() { private SettingsBuilder newset() {

View file

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

View file

@ -36,12 +36,8 @@ import ghidra.program.model.mem.ByteMemBufferImpl;
public class CharDataTypesRenderTest extends AbstractGTest { public class CharDataTypesRenderTest extends AbstractGTest {
private ByteMemBufferImpl mb(boolean isBE, int... values) { 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); 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() { private SettingsBuilder newset() {

View file

@ -29,53 +29,53 @@ public class Float10DataTypeTest extends AbstractGTest {
@Test @Test
public void testGetValue() { 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 = Object value =
Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
Assert.assertEquals(FloatFormat.BIG_POSITIVE_INFINITY, value); 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 = value =
Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
Assert.assertEquals(FloatFormat.BIG_NEGATIVE_INFINITY, value); 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 = value =
Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
Assert.assertEquals(FloatFormat.BIG_NaN, value); Assert.assertEquals(FloatFormat.BIG_NaN, value);
// Really small values // 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 = value =
Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
Assert.assertEquals("5.04315471466814026E-4932", value.toString()); 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 = value =
Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
Assert.assertEquals("-5.04315471466814026E-4932", value.toString()); Assert.assertEquals("-5.04315471466814026E-4932", value.toString());
// Really big values // 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 = value =
Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
Assert.assertEquals("8.92298621517923824E+4931", value.toString()); 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 = value =
Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
Assert.assertEquals("-8.92298621517923824E+4931", value.toString()); Assert.assertEquals("-8.92298621517923824E+4931", value.toString());
// Values within the range of Double // 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 = value =
Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
Assert.assertEquals(BigDecimal.valueOf(4.5), value); 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 = value =
Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10); Float10DataType.dataType.getValue(new ByteMemBufferImpl(null, bytes, true), null, 10);
Assert.assertEquals(BigDecimal.valueOf(-4.5), value); 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) { 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); 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() { private SettingsBuilder newset() {

View file

@ -80,14 +80,6 @@ public class ViewStringsPluginScreenShots extends GhidraScreenShotGenerator {
} }
private static byte[] bytes(int... intValues) {
byte[] result = new byte[intValues.length];
for (int i = 0; i < intValues.length; i++) {
result[i] = (byte) (intValues[i]);
}
return result;
}
@Test @Test
public void testDefined_String_Table() { public void testDefined_String_Table() {
ViewStringsProvider provider = showProvider(ViewStringsProvider.class); ViewStringsProvider provider = showProvider(ViewStringsProvider.class);