mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
GP-24_emteere fixing disassembly during emulation
This commit is contained in:
parent
b3b7bab4ca
commit
27f9b750db
4 changed files with 403 additions and 54 deletions
|
@ -0,0 +1,282 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.mem;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
import ghidra.util.task.TaskMonitorAdapter;
|
||||
|
||||
public class WrappedMemoryBufferTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
private Program program;
|
||||
private MemBuffer memBuf;
|
||||
|
||||
public WrappedMemoryBufferTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
private void loadProgram(String name) throws Exception {
|
||||
ProgramBuilder builder = new ProgramBuilder(name, ProgramBuilder._TOY);
|
||||
builder.createMemory("ram", "0x0", 100000);
|
||||
program = builder.getProgram();
|
||||
memBuf = new MemoryBufferImpl(program.getMemory(), program.getMinAddress());
|
||||
memBuf = new WrappedMemBuffer(memBuf, 20, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBytes() throws Exception {
|
||||
loadProgram("notepad");
|
||||
|
||||
Address minAddr = program.getMinAddress();
|
||||
Address maxAddr = program.getMaxAddress();
|
||||
setBytes(minAddr, new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 });
|
||||
setBytes(maxAddr.subtract(7), new byte[] { 11, 12, 13, 14, 15, 16, 17, 18 });
|
||||
|
||||
memBuf = new MemoryBufferImpl(program.getMemory(), minAddr);
|
||||
memBuf = new WrappedMemBuffer(memBuf, 5, 0);
|
||||
byte[] bytes = new byte[4];
|
||||
assertEquals(4, memBuf.getBytes(bytes, 0));
|
||||
Assert.assertArrayEquals("Unexpected bytes read from memBuf", new byte[] { 1, 2, 3, 4 },
|
||||
bytes);
|
||||
assertEquals(4, memBuf.getBytes(bytes, 4));
|
||||
Assert.assertArrayEquals("Unexpected bytes read from memBuf", new byte[] { 5, 6, 7, 8 },
|
||||
bytes);
|
||||
|
||||
Arrays.fill(bytes, (byte) 0);
|
||||
assertEquals(2, memBuf.getBytes(bytes, 99998));
|
||||
Assert.assertArrayEquals("Unexpected bytes read from memBuf", new byte[] { 17, 18, 0, 0 },
|
||||
bytes);
|
||||
assertEquals(4, memBuf.getBytes(bytes, 99996));
|
||||
Assert.assertArrayEquals("Unexpected bytes read from memBuf", new byte[] { 15, 16, 17, 18 },
|
||||
bytes);
|
||||
assertEquals(4, memBuf.getBytes(bytes, 99995));
|
||||
Assert.assertArrayEquals("Unexpected bytes read from memBuf", new byte[] { 14, 15, 16, 17 },
|
||||
bytes);
|
||||
Arrays.fill(bytes, (byte) 0);
|
||||
assertEquals(0, memBuf.getBytes(bytes, 100000));
|
||||
Assert.assertArrayEquals("Unexpected bytes read from memBuf", new byte[] { 0, 0, 0, 0 },
|
||||
bytes);
|
||||
}
|
||||
|
||||
private void setBytes(Address addr, byte[] bytes) throws MemoryAccessException {
|
||||
|
||||
Memory mem = program.getMemory();
|
||||
int txId = program.startTransaction("Test");
|
||||
try {
|
||||
mem.setBytes(addr, bytes);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(txId, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSetPosition() throws Exception {
|
||||
loadProgram("notepad");
|
||||
|
||||
Memory mem = program.getMemory();
|
||||
Address addr = program.getMinAddress();
|
||||
memBuf = new MemoryBufferImpl(mem, program.getMinAddress());
|
||||
WrappedMemBuffer wrapBuf = new WrappedMemBuffer(memBuf, 5, 0);
|
||||
for (int i = 0; i < 5000; i++) {
|
||||
assertEquals(mem.getByte(addr), wrapBuf.getByte(0));
|
||||
assertEquals(mem.getByte(addr.add(1)), wrapBuf.getByte(1));
|
||||
assertEquals(mem.getByte(addr.add(2)), wrapBuf.getByte(2));
|
||||
assertEquals(mem.getByte(addr.add(3)), wrapBuf.getByte(3));
|
||||
addr = addr.add(5);
|
||||
int offset = (int) addr.subtract(program.getMinAddress());
|
||||
wrapBuf.setBaseOffset(offset);
|
||||
}
|
||||
|
||||
addr = program.getMinAddress();
|
||||
memBuf = new MemoryBufferImpl(mem, program.getMinAddress());
|
||||
wrapBuf = new WrappedMemBuffer(memBuf, 5, 0);
|
||||
for (int i = 0; i < 500; i++) {
|
||||
assertEquals(mem.getByte(addr), memBuf.getByte(0));
|
||||
assertEquals(mem.getByte(addr.add(1)), memBuf.getByte(1));
|
||||
assertEquals(mem.getByte(addr.add(2)), memBuf.getByte(2));
|
||||
assertEquals(mem.getByte(addr.add(3)), memBuf.getByte(3));
|
||||
addr = addr.add(50);
|
||||
int offset = (int) addr.subtract(program.getMinAddress());
|
||||
wrapBuf.setBaseOffset(offset);
|
||||
}
|
||||
|
||||
addr = program.getMinAddress();
|
||||
memBuf = new MemoryBufferImpl(mem, program.getMinAddress());
|
||||
wrapBuf = new WrappedMemBuffer(memBuf, 5, 0);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
assertEquals(mem.getByte(addr), wrapBuf.getByte(0));
|
||||
assertEquals(mem.getByte(addr.add(1)), wrapBuf.getByte(1));
|
||||
assertEquals(mem.getByte(addr.add(2)), wrapBuf.getByte(2));
|
||||
assertEquals(mem.getByte(addr.add(3)), wrapBuf.getByte(3));
|
||||
addr = addr.add(2000);
|
||||
int offset = (int) addr.subtract(program.getMinAddress());
|
||||
wrapBuf.setBaseOffset(offset);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProgram20bit() throws Exception {
|
||||
program =
|
||||
createDefaultProgram(testName.getMethodName(), ProgramBuilder._X86_16_REAL_MODE, this);
|
||||
|
||||
Address start = program.getAddressFactory().getAddress("0000:0000");
|
||||
|
||||
InputStream is = new InputStream() {
|
||||
private int pos = 0;
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (pos < 0x10000) {
|
||||
++pos;
|
||||
return 0xaa;
|
||||
}
|
||||
if (pos < 0x20000) {
|
||||
++pos;
|
||||
return 0xbb;
|
||||
}
|
||||
if (pos < 0x30000) {
|
||||
++pos;
|
||||
return 0xcc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
int id = program.startTransaction("add block");
|
||||
try {
|
||||
program.getMemory().createInitializedBlock(".test", start, is, 0x30000,
|
||||
TaskMonitorAdapter.DUMMY_MONITOR, false);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(id, true);
|
||||
}
|
||||
|
||||
MemoryBufferImpl buf = new MemoryBufferImpl(program.getMemory(), start);
|
||||
|
||||
WrappedMemBuffer wrapBuf = new WrappedMemBuffer(buf, 0);
|
||||
for (int i = 0; i < 0x30000; i++) {
|
||||
int b = 0xff & wrapBuf.getByte(i);
|
||||
if (i < 0x10000) {
|
||||
assertEquals(0xaa, b);
|
||||
continue;
|
||||
}
|
||||
if (i < 0x20000) {
|
||||
assertEquals(0xbb, b);
|
||||
continue;
|
||||
}
|
||||
if (i < 0x30000) {
|
||||
assertEquals(0xcc, b);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
wrapBuf = new WrappedMemBuffer(buf, 10, 0);
|
||||
for (int i = 0; i < 0x30000; i++) {
|
||||
int b = 0xff & wrapBuf.getByte(i);
|
||||
if (i < 0x10000) {
|
||||
assertEquals(0xaa, b);
|
||||
continue;
|
||||
}
|
||||
if (i < 0x20000) {
|
||||
assertEquals(0xbb, b);
|
||||
continue;
|
||||
}
|
||||
if (i < 0x30000) {
|
||||
assertEquals(0xcc, b);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBoundary() throws Exception {
|
||||
loadProgram("notepad");
|
||||
|
||||
Memory mem = program.getMemory();
|
||||
Address addr = program.getMaxAddress();
|
||||
memBuf = new MemoryBufferImpl(mem, program.getMaxAddress());
|
||||
WrappedMemBuffer wrapBuf = new WrappedMemBuffer(memBuf, 0);
|
||||
|
||||
assertEquals(mem.getByte(addr), wrapBuf.getByte(0));
|
||||
|
||||
wrapBuf.setBaseOffset(1);
|
||||
|
||||
try {
|
||||
wrapBuf.getByte(0);
|
||||
Assert.fail("Should not have been able to get byte");
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
// good
|
||||
}
|
||||
|
||||
wrapBuf = new WrappedMemBuffer(memBuf, 20, 0);
|
||||
|
||||
assertEquals(mem.getByte(addr), wrapBuf.getByte(0));
|
||||
|
||||
wrapBuf.setBaseOffset(1);
|
||||
|
||||
try {
|
||||
wrapBuf.getByte(0);
|
||||
Assert.fail("Should not have been able to get byte");
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
// good
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBoundary1() throws Exception {
|
||||
loadProgram("notepad");
|
||||
|
||||
Memory mem = program.getMemory();
|
||||
Address addr = program.getMaxAddress();
|
||||
memBuf = new MemoryBufferImpl(mem, program.getMaxAddress());
|
||||
WrappedMemBuffer wrapBuf = new WrappedMemBuffer(memBuf, 0);
|
||||
|
||||
assertEquals(mem.getByte(addr), wrapBuf.getByte(0));
|
||||
try {
|
||||
wrapBuf.getByte(1);
|
||||
Assert.fail("Should not have been able to get byte");
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
// good
|
||||
}
|
||||
|
||||
wrapBuf = new WrappedMemBuffer(memBuf, 20, 0);
|
||||
|
||||
assertEquals(mem.getByte(addr), wrapBuf.getByte(0));
|
||||
try {
|
||||
wrapBuf.getByte(1);
|
||||
Assert.fail("Should not have been able to get byte");
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
// good
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -920,9 +920,8 @@ public class Disassembler implements DisassemblerConflictHandler {
|
|||
|
||||
disassemblerContext.flowToAddress(addr);
|
||||
|
||||
// TODO: An overall better caching of bytes for this block could be done instead
|
||||
// the previous buffering done here was not doing any buffering
|
||||
MemBuffer instrMemBuffer = new DumbMemBufferImpl(blockMemBuffer.getMemory(), addr);
|
||||
MemBuffer instrMemBuffer = new WrappedMemBuffer(blockMemBuffer,
|
||||
(int) addr.subtract(blockMemBuffer.getAddress()));
|
||||
|
||||
adjustPreParseContext(instrMemBuffer);
|
||||
|
||||
|
|
|
@ -15,12 +15,11 @@
|
|||
*/
|
||||
package ghidra.program.model.mem;
|
||||
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.util.GhidraBigEndianDataConverter;
|
||||
import ghidra.util.GhidraLittleEndianDataConverter;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.util.GhidraDataConverter;
|
||||
|
||||
/**
|
||||
* MemBufferImpl implements the MemBuffer interface. It buffers up N bytes
|
||||
* at time, reducing the overall number of calls to Memory, greatly reducing
|
||||
|
@ -34,8 +33,9 @@ import java.math.BigInteger;
|
|||
|
||||
public class MemoryBufferImpl implements MutableMemBuffer {
|
||||
|
||||
private final GhidraDataConverter converter;
|
||||
|
||||
private static final int DEFAULT_BUFSIZE = 1024;
|
||||
private static final int THRESH = 8;
|
||||
|
||||
private Memory mem;
|
||||
private Address startAddr;
|
||||
|
@ -43,6 +43,7 @@ public class MemoryBufferImpl implements MutableMemBuffer {
|
|||
private int startAddrIndex = 0;
|
||||
private int minOffset = 0;
|
||||
private int maxOffset = -1;
|
||||
private int threshold = 0;
|
||||
|
||||
/**
|
||||
* Construct a new MemoryBufferImpl
|
||||
|
@ -62,6 +63,9 @@ public class MemoryBufferImpl implements MutableMemBuffer {
|
|||
public MemoryBufferImpl(Memory mem, Address addr, int bufSize) {
|
||||
this.mem = mem;
|
||||
buffer = new byte[bufSize];
|
||||
threshold = bufSize / 100; // 1/100 of buffer size
|
||||
|
||||
this.converter = GhidraDataConverter.getInstance(mem.isBigEndian());
|
||||
setPosition(addr);
|
||||
}
|
||||
|
||||
|
@ -81,7 +85,7 @@ public class MemoryBufferImpl implements MutableMemBuffer {
|
|||
if (minOffset <= maxOffset) {
|
||||
if (addr.getAddressSpace().equals(startAddr.getAddressSpace())) {
|
||||
long diff = addr.subtract(startAddr);
|
||||
if (diff >= minOffset && diff < maxOffset - THRESH) {
|
||||
if (diff >= minOffset && diff < maxOffset - threshold) {
|
||||
startAddr = addr;
|
||||
minOffset -= (int) diff;
|
||||
maxOffset -= (int) diff;
|
||||
|
@ -155,35 +159,22 @@ public class MemoryBufferImpl implements MutableMemBuffer {
|
|||
|
||||
@Override
|
||||
public short getShort(int offset) throws MemoryAccessException {
|
||||
if (mem.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 (mem.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 (mem.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 (mem.isBigEndian()) {
|
||||
return GhidraBigEndianDataConverter.INSTANCE.getBigInteger(this, offset, size, signed);
|
||||
return converter.getBigInteger(this, offset, size, signed);
|
||||
}
|
||||
return GhidraLittleEndianDataConverter.INSTANCE.getBigInteger(this, offset, size, signed);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,13 +19,24 @@ import java.math.BigInteger;
|
|||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressOutOfBoundsException;
|
||||
import ghidra.util.GhidraDataConverter;
|
||||
|
||||
public class WrappedMemBuffer implements MemBuffer {
|
||||
|
||||
private final GhidraDataConverter converter;
|
||||
|
||||
private final MemBuffer memBuffer;
|
||||
private int baseOffset;
|
||||
private Address address;
|
||||
|
||||
private static final int DEFAULT_BUFSIZE = 10;
|
||||
|
||||
private byte[] buffer;
|
||||
private int subBufferIndex = 0;
|
||||
private int minOffset = 0;
|
||||
private int maxOffset = -1;
|
||||
private int threshold = 0;
|
||||
|
||||
/**
|
||||
* Construct a wrapped MemBuffer with an adjustable base offset
|
||||
* @param buf memory buffer
|
||||
|
@ -33,23 +44,60 @@ public class WrappedMemBuffer implements MemBuffer {
|
|||
* @throws AddressOutOfBoundsException
|
||||
*/
|
||||
public WrappedMemBuffer(MemBuffer buf, int offset) throws AddressOutOfBoundsException {
|
||||
this(buf, DEFAULT_BUFSIZE, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a wrapped MemBuffer with an adjustable base offset
|
||||
* @param buf memory buffer
|
||||
* @buffersize size of cache buffer - specify 0 for no buffering
|
||||
* @param offset base offset for this buffer relative to buf's address
|
||||
* @throws AddressOutOfBoundsException
|
||||
*/
|
||||
public WrappedMemBuffer(MemBuffer buf, int bufferSize, int offset)
|
||||
throws AddressOutOfBoundsException {
|
||||
this.memBuffer = buf;
|
||||
this.converter = GhidraDataConverter.getInstance(buf.isBigEndian());
|
||||
|
||||
buffer = new byte[bufferSize];
|
||||
threshold = bufferSize / 100; // 1/100 of buffer size
|
||||
|
||||
setBaseOffset(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set new base offset relative to the associated MemBuffer's address
|
||||
* @param offset new base offset of this buffer
|
||||
* @throws AddressOutOfBoundsException
|
||||
*/
|
||||
public void setBaseOffset(int offset) throws AddressOutOfBoundsException {
|
||||
this.baseOffset = offset;
|
||||
this.address = memBuffer.getAddress().add(baseOffset);
|
||||
}
|
||||
this.address = memBuffer.getAddress().add(offset);
|
||||
|
||||
@Override
|
||||
public Address getAddress() {
|
||||
return address;
|
||||
// already set, changing position
|
||||
if (minOffset <= maxOffset) {
|
||||
long diff = offset - baseOffset;
|
||||
if (diff >= minOffset && diff < (maxOffset - threshold)) {
|
||||
baseOffset = offset;
|
||||
minOffset -= (int) diff;
|
||||
maxOffset -= (int) diff;
|
||||
subBufferIndex += diff;
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.baseOffset = offset;
|
||||
|
||||
if (buffer.length > 0) {
|
||||
subBufferIndex = 0;
|
||||
minOffset = 0;
|
||||
maxOffset = -1;
|
||||
|
||||
maxOffset = memBuffer.getBytes(buffer, baseOffset) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -70,11 +118,40 @@ public class WrappedMemBuffer implements MemBuffer {
|
|||
|
||||
@Override
|
||||
public byte getByte(int offset) throws MemoryAccessException {
|
||||
// no buffering, just get the byte
|
||||
if (buffer.length <= 0) {
|
||||
return memBuffer.getByte(computeOffset(offset));
|
||||
}
|
||||
|
||||
// byte found in buffer
|
||||
if ((offset >= minOffset) && (offset <= maxOffset)) {
|
||||
return buffer[subBufferIndex + offset];
|
||||
}
|
||||
|
||||
// fill the buffer
|
||||
int nRead = memBuffer.getBytes(buffer, computeOffset(offset));
|
||||
|
||||
subBufferIndex = -offset;
|
||||
minOffset = offset;
|
||||
maxOffset = offset + nRead - 1;
|
||||
|
||||
if (nRead == 0) {
|
||||
throw new MemoryAccessException();
|
||||
}
|
||||
return buffer[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBytes(byte[] b, int offset) {
|
||||
if (buffer.length > 0) {
|
||||
// bytes are contained in the buffer
|
||||
if (offset >= minOffset && (b.length + offset) <= maxOffset) {
|
||||
System.arraycopy(buffer, subBufferIndex + offset, b, 0, b.length);
|
||||
return b.length;
|
||||
}
|
||||
}
|
||||
|
||||
// grab from wrapped buffer, too many bytes, or no buffer
|
||||
try {
|
||||
return memBuffer.getBytes(b, computeOffset(offset));
|
||||
}
|
||||
|
@ -83,34 +160,34 @@ public class WrappedMemBuffer implements MemBuffer {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(int offset) throws MemoryAccessException {
|
||||
return memBuffer.getInt(computeOffset(offset));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(int offset) throws MemoryAccessException {
|
||||
return memBuffer.getLong(computeOffset(offset));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger getBigInteger(int offset, int size, boolean signed)
|
||||
throws MemoryAccessException {
|
||||
return memBuffer.getBigInteger(computeOffset(offset), size, signed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Memory getMemory() {
|
||||
return memBuffer.getMemory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getShort(int offset) throws MemoryAccessException {
|
||||
return memBuffer.getShort(computeOffset(offset));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBigEndian() {
|
||||
return memBuffer.isBigEndian();
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getShort(int offset) throws MemoryAccessException {
|
||||
return converter.getShort(this, computeOffset(offset));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(int offset) throws MemoryAccessException {
|
||||
return converter.getInt(this, computeOffset(offset));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(int offset) throws MemoryAccessException {
|
||||
return converter.getLong(this, computeOffset(offset));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger getBigInteger(int offset, int size, boolean signed)
|
||||
throws MemoryAccessException {
|
||||
return converter.getBigInteger(this, computeOffset(offset), size, signed);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue