GP-24_emteere fixing disassembly during emulation

This commit is contained in:
emteere 2020-06-30 16:56:33 -04:00
parent b3b7bab4ca
commit 27f9b750db
4 changed files with 403 additions and 54 deletions

View file

@ -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);

View file

@ -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 GhidraLittleEndianDataConverter.INSTANCE.getBigInteger(this, offset, size, signed);
return converter.getBigInteger(this, offset, size, signed);
}
}

View file

@ -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 {
return memBuffer.getByte(computeOffset(offset));
// 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);
}
}