mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
GP-3256 Added support for Instruction length-override
This commit is contained in:
parent
a820a36e94
commit
aefb7f2aed
67 changed files with 1895 additions and 574 deletions
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package ghidra.trace.database.listing;
|
||||
|
||||
import static ghidra.lifecycle.Unfinished.TODO;
|
||||
import static ghidra.lifecycle.Unfinished.*;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
|
@ -278,11 +278,6 @@ public interface DBTraceCodeUnitAdapter extends TraceCodeUnit, MemBufferMixin {
|
|||
return DBTraceCommentAdapter.arrayFromComment(getComment(commentType));
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean isSuccessor(CodeUnit codeUnit) {
|
||||
return getMaxAddress().isSuccessor(codeUnit.getMinAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean contains(Address testAddr) {
|
||||
return getMinAddress().compareTo(testAddr) <= 0 && testAddr.compareTo(getMaxAddress()) <= 0;
|
||||
|
|
|
@ -21,12 +21,14 @@ import java.nio.ByteBuffer;
|
|||
import java.util.*;
|
||||
|
||||
import db.DBRecord;
|
||||
import ghidra.program.database.code.InstructionDB;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.ContextChangeException;
|
||||
import ghidra.program.model.listing.FlowOverride;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.trace.database.DBTrace;
|
||||
import ghidra.trace.database.DBTraceUtils;
|
||||
import ghidra.trace.database.context.DBTraceRegisterContextManager;
|
||||
|
@ -36,7 +38,7 @@ import ghidra.trace.database.guest.InternalTracePlatform;
|
|||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree;
|
||||
import ghidra.trace.database.symbol.DBTraceReference;
|
||||
import ghidra.trace.database.symbol.DBTraceReferenceSpace;
|
||||
import ghidra.trace.model.Lifespan;
|
||||
import ghidra.trace.model.*;
|
||||
import ghidra.trace.model.Trace.TraceInstructionChangeType;
|
||||
import ghidra.trace.model.guest.TracePlatform;
|
||||
import ghidra.trace.model.listing.TraceInstruction;
|
||||
|
@ -52,17 +54,21 @@ import ghidra.util.database.annot.*;
|
|||
* The implementation of {@link TraceInstruction} for {@link DBTrace}
|
||||
*/
|
||||
@DBAnnotatedObjectInfo(version = 0)
|
||||
public class DBTraceInstruction extends AbstractDBTraceCodeUnit<DBTraceInstruction> implements
|
||||
TraceInstruction, InstructionAdapterFromPrototype, InstructionContext {
|
||||
public class DBTraceInstruction extends AbstractDBTraceCodeUnit<DBTraceInstruction>
|
||||
implements TraceInstruction, InstructionAdapterFromPrototype, InstructionContext {
|
||||
private static final Address[] EMPTY_ADDRESS_ARRAY = new Address[] {};
|
||||
private static final String TABLE_NAME = "Instructions";
|
||||
|
||||
private static final byte FALLTHROUGH_SET_MASK = 0x01;
|
||||
private static final byte FALLTHROUGH_CLEAR_MASK = ~FALLTHROUGH_SET_MASK;
|
||||
|
||||
private static final byte FLOWOVERRIDE_SET_MASK = 0x0e;
|
||||
private static final byte FLOWOVERRIDE_CLEAR_MASK = ~FLOWOVERRIDE_SET_MASK;
|
||||
private static final int FLOWOVERRIDE_SHIFT = 1;
|
||||
private static final byte FLOW_OVERRIDE_SET_MASK = 0x0e;
|
||||
private static final byte FLOW_OVERRIDE_CLEAR_MASK = ~FLOW_OVERRIDE_SET_MASK;
|
||||
private static final int FLOW_OVERRIDE_SHIFT = 1;
|
||||
|
||||
private static final byte LENGTH_OVERRIDE_SET_MASK = 0x70;
|
||||
private static final byte LENGTH_OVERRIDE_CLEAR_MASK = ~LENGTH_OVERRIDE_SET_MASK;
|
||||
private static final int LENGTH_OVERRIDE_SHIFT = 4;
|
||||
|
||||
static final String PLATFORM_COLUMN_NAME = "Platform";
|
||||
static final String PROTOTYPE_COLUMN_NAME = "Prototype";
|
||||
|
@ -143,6 +149,7 @@ public class DBTraceInstruction extends AbstractDBTraceCodeUnit<DBTraceInstructi
|
|||
|
||||
protected InstructionPrototype prototype;
|
||||
protected FlowOverride flowOverride;
|
||||
protected int lengthOverride;
|
||||
|
||||
protected ParserContext parserContext;
|
||||
protected InternalTracePlatform platform;
|
||||
|
@ -186,18 +193,24 @@ public class DBTraceInstruction extends AbstractDBTraceCodeUnit<DBTraceInstructi
|
|||
* @param platform the platform
|
||||
* @param prototype the instruction prototype
|
||||
* @param context the context for locating or creating the prototype entry
|
||||
* @param forcedLengthOverride reduced instruction byte-length (1..7) or 0 to use default length
|
||||
*/
|
||||
protected void set(InternalTracePlatform platform, InstructionPrototype prototype,
|
||||
ProcessorContextView context) {
|
||||
ProcessorContextView context, int forcedLengthOverride) {
|
||||
this.platformKey = platform.getIntKey();
|
||||
// NOTE: Using "this" for the MemBuffer seems a bit precarious.
|
||||
DBTraceGuestLanguage languageEntry = platform == null ? null : platform.getLanguageEntry();
|
||||
this.prototypeKey = (int) space.manager
|
||||
.findOrRecordPrototype(prototype, languageEntry, this, context)
|
||||
.getKey();
|
||||
DBTraceGuestLanguage languageEntry = platform.getLanguageEntry();
|
||||
this.prototypeKey =
|
||||
(int) space.manager.findOrRecordPrototype(prototype, languageEntry, this, context)
|
||||
.getKey();
|
||||
this.flowOverride = FlowOverride.NONE; // flags field is already consistent
|
||||
this.lengthOverride = 0;
|
||||
update(PLATFORM_COLUMN, PROTOTYPE_COLUMN, FLAGS_COLUMN);
|
||||
|
||||
if (forcedLengthOverride != 0) {
|
||||
updateLengthOverride(forcedLengthOverride);
|
||||
}
|
||||
|
||||
// TODO: Can there be more in this context than the context register???
|
||||
doSetPlatformMapping(platform);
|
||||
this.prototype = prototype;
|
||||
|
@ -216,12 +229,19 @@ public class DBTraceInstruction extends AbstractDBTraceCodeUnit<DBTraceInstructi
|
|||
}
|
||||
prototype = space.manager.getPrototypeByKey(prototypeKey);
|
||||
if (prototype == null) {
|
||||
Msg.error(this,
|
||||
"Instruction table is corrupt for address " + getMinAddress() +
|
||||
". Missing prototype " + prototypeKey);
|
||||
Msg.error(this, "Instruction table is corrupt for address " + getMinAddress() +
|
||||
". Missing prototype " + prototypeKey);
|
||||
prototype = new InvalidPrototype(getTrace().getBaseLanguage());
|
||||
}
|
||||
flowOverride = FlowOverride.values()[(flags & FLOWOVERRIDE_SET_MASK) >> FLOWOVERRIDE_SHIFT];
|
||||
flowOverride =
|
||||
FlowOverride.values()[(flags & FLOW_OVERRIDE_SET_MASK) >> FLOW_OVERRIDE_SHIFT];
|
||||
|
||||
lengthOverride = (flags & LENGTH_OVERRIDE_SET_MASK) >> LENGTH_OVERRIDE_SHIFT;
|
||||
if (lengthOverride != 0 && lengthOverride < prototype.getLength()) {
|
||||
Address minAddr = getMinAddress();
|
||||
Address newEndAddr = minAddr.add(lengthOverride - 1);
|
||||
doSetRange(new AddressRangeImpl(minAddr, newEndAddr));
|
||||
}
|
||||
|
||||
doSetPlatformMapping(platform);
|
||||
}
|
||||
|
@ -334,8 +354,7 @@ public class DBTraceInstruction extends AbstractDBTraceCodeUnit<DBTraceInstructi
|
|||
if (flowType.hasFallthrough()) {
|
||||
try {
|
||||
return instructionContext.getAddress()
|
||||
.addNoWrap(
|
||||
prototype.getFallThroughOffset(instructionContext));
|
||||
.addNoWrap(prototype.getFallThroughOffset(instructionContext));
|
||||
}
|
||||
catch (AddressOverflowException e) {
|
||||
return null;
|
||||
|
@ -364,6 +383,9 @@ public class DBTraceInstruction extends AbstractDBTraceCodeUnit<DBTraceInstructi
|
|||
}
|
||||
return null;
|
||||
}
|
||||
if (lengthOverride != 0 && getFlowType().hasFallthrough()) {
|
||||
return getMinAddress().add(lengthOverride);
|
||||
}
|
||||
return getDefaultFallThrough();
|
||||
}
|
||||
}
|
||||
|
@ -433,6 +455,10 @@ public class DBTraceInstruction extends AbstractDBTraceCodeUnit<DBTraceInstructi
|
|||
return EMPTY_ADDRESS_ARRAY;
|
||||
}
|
||||
|
||||
if (lengthOverride != 0 && getFlowType().hasFallthrough()) {
|
||||
list.add(getMinAddress().add(lengthOverride));
|
||||
}
|
||||
|
||||
return list.toArray(new Address[list.size()]);
|
||||
}
|
||||
}
|
||||
|
@ -526,8 +552,8 @@ public class DBTraceInstruction extends AbstractDBTraceCodeUnit<DBTraceInstructi
|
|||
}
|
||||
FlowType origFlowType = getFlowType();
|
||||
|
||||
flags &= FLOWOVERRIDE_CLEAR_MASK;
|
||||
flags |= (flowOverride.ordinal() << FLOWOVERRIDE_SHIFT) & FLOWOVERRIDE_SET_MASK;
|
||||
flags &= FLOW_OVERRIDE_CLEAR_MASK;
|
||||
flags |= (flowOverride.ordinal() << FLOW_OVERRIDE_SHIFT) & FLOW_OVERRIDE_SET_MASK;
|
||||
this.flowOverride = flowOverride;
|
||||
update(FLAGS_COLUMN);
|
||||
|
||||
|
@ -545,8 +571,91 @@ public class DBTraceInstruction extends AbstractDBTraceCodeUnit<DBTraceInstructi
|
|||
}
|
||||
}
|
||||
space.trace.setChanged(
|
||||
new TraceChangeRecord<>(TraceInstructionChangeType.FLOW_OVERRIDE_CHANGED,
|
||||
space, this, oldFlowOverride, flowOverride));
|
||||
new TraceChangeRecord<>(TraceInstructionChangeType.FLOW_OVERRIDE_CHANGED, space, this,
|
||||
oldFlowOverride, flowOverride));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLengthOverride(int length) throws CodeUnitInsertionException {
|
||||
int oldLengthOverride = this.lengthOverride;
|
||||
try (LockHold hold = space.trace.lockWrite()) {
|
||||
checkDeleted();
|
||||
InstructionPrototype proto = getPrototype();
|
||||
length = InstructionDB.checkLengthOverride(length, proto);
|
||||
if (length == lengthOverride) {
|
||||
return; // no change
|
||||
}
|
||||
|
||||
int newLength = length != 0 ? length : proto.getLength();
|
||||
if (newLength > getLength()) {
|
||||
Address minAddr = getMinAddress();
|
||||
Address newEndAddr = minAddr.add(newLength - 1);
|
||||
TraceAddressSnapRange tasr = new ImmutableTraceAddressSnapRange(
|
||||
new AddressRangeImpl(minAddr.next(), newEndAddr), getLifespan());
|
||||
for (AbstractDBTraceCodeUnit<?> cu : space.definedUnits.getIntersecting(tasr)) {
|
||||
if (cu != this) {
|
||||
throw new CodeUnitInsertionException(
|
||||
"Length override of " + newLength + " conflicts with code unit at " +
|
||||
cu.getMinAddress() + ", lifespan=" + cu.getLifespan());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateLengthOverride(length);
|
||||
}
|
||||
space.trace.setChanged(
|
||||
new TraceChangeRecord<>(TraceInstructionChangeType.LENGTH_OVERRIDE_CHANGED, space, this,
|
||||
oldLengthOverride, length));
|
||||
}
|
||||
|
||||
private void updateLengthOverride(int length) {
|
||||
flags &= LENGTH_OVERRIDE_CLEAR_MASK;
|
||||
flags |= (length << LENGTH_OVERRIDE_SHIFT);
|
||||
lengthOverride = length;
|
||||
update(FLAGS_COLUMN);
|
||||
|
||||
int newLength = length != 0 ? length : getPrototype().getLength();
|
||||
Address minAddr = getMinAddress();
|
||||
Address newEndAddr = minAddr.add(newLength - 1);
|
||||
doSetRange(new AddressRangeImpl(minAddr, newEndAddr));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLengthOverridden() {
|
||||
return lengthOverride != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
if (lengthOverride != 0) {
|
||||
return lengthOverride;
|
||||
}
|
||||
return super.getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getParsedLength() {
|
||||
if (lengthOverride == 0) {
|
||||
return super.getLength();
|
||||
}
|
||||
return getPrototype().getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getParsedBytes() throws MemoryAccessException {
|
||||
if (!isLengthOverridden()) {
|
||||
return getBytes();
|
||||
}
|
||||
try (LockHold hold = LockHold.lock(space.lock.readLock())) {
|
||||
checkIsValid();
|
||||
int len = getPrototype().getLength();
|
||||
byte[] b = new byte[len];
|
||||
Address addr = getAddress();
|
||||
if (len != getMemory().getBytes(addr, b)) {
|
||||
throw new MemoryAccessException("Failed to read " + len + " bytes at " + addr);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -622,8 +731,8 @@ public class DBTraceInstruction extends AbstractDBTraceCodeUnit<DBTraceInstructi
|
|||
}
|
||||
update(FLAGS_COLUMN);
|
||||
space.trace.setChanged(
|
||||
new TraceChangeRecord<>(TraceInstructionChangeType.FALL_THROUGH_OVERRIDE_CHANGED,
|
||||
space, this, !overridden, overridden));
|
||||
new TraceChangeRecord<>(TraceInstructionChangeType.FALL_THROUGH_OVERRIDE_CHANGED, space,
|
||||
this, !overridden, overridden));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -59,9 +59,10 @@ public class DBTraceInstructionsMemoryView
|
|||
@Override
|
||||
public DBTraceInstruction create(Lifespan lifespan, Address address,
|
||||
TracePlatform platform, InstructionPrototype prototype,
|
||||
ProcessorContextView context) throws CodeUnitInsertionException {
|
||||
ProcessorContextView context, int forcedLengthOverride)
|
||||
throws CodeUnitInsertionException {
|
||||
return delegateWrite(address.getAddressSpace(),
|
||||
m -> m.create(lifespan, address, platform, prototype, context));
|
||||
m -> m.create(lifespan, address, platform, prototype, context, forcedLengthOverride));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.util.*;
|
|||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import ghidra.program.database.code.InstructionDB;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.lang.InstructionError.InstructionErrorType;
|
||||
|
@ -103,16 +104,22 @@ public class DBTraceInstructionsView extends AbstractBaseDBTraceDefinedUnitsView
|
|||
protected boolean isSuitable(Instruction candidate, Instruction protoInstr) {
|
||||
try {
|
||||
return candidate.getPrototype().equals(protoInstr.getPrototype()) &&
|
||||
Arrays.equals(candidate.getBytes(), protoInstr.getBytes()) &&
|
||||
candidate.isFallThroughOverridden() == protoInstr.isFallThroughOverridden() &&
|
||||
Objects.equals(candidate.getFallThrough(), protoInstr.getFallThrough()) &&
|
||||
candidate.getFlowOverride() == protoInstr.getFlowOverride();
|
||||
candidate.getFlowOverride() == protoInstr.getFlowOverride() &&
|
||||
candidate.getLength() == protoInstr.getLength() && // handles potential length override
|
||||
hasSameBytes(candidate, protoInstr);
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasSameBytes(Instruction instr1, Instruction instr2)
|
||||
throws MemoryAccessException {
|
||||
return Arrays.equals(instr1.getParsedBytes(), instr2.getParsedBytes());
|
||||
}
|
||||
|
||||
protected Instruction doAdjustExisting(Address address, Instruction protoInstr)
|
||||
throws AddressOverflowException, CancelledException, CodeUnitInsertionException {
|
||||
DBTraceInstruction exists = getAt(lifespan.lmin(), address);
|
||||
|
@ -193,8 +200,8 @@ public class DBTraceInstructionsView extends AbstractBaseDBTraceDefinedUnitsView
|
|||
return prec;
|
||||
}
|
||||
|
||||
Instruction created =
|
||||
doCreate(lifespan, address, platform, protoInstr.getPrototype(), protoInstr);
|
||||
Instruction created = doCreate(lifespan, address, platform,
|
||||
protoInstr.getPrototype(), protoInstr, protoInstr.getLength());
|
||||
// copy override settings to replacement instruction
|
||||
if (protoInstr.isFallThroughOverridden()) {
|
||||
created.setFallThrough(protoInstr.getFallThrough());
|
||||
|
@ -336,20 +343,30 @@ public class DBTraceInstructionsView extends AbstractBaseDBTraceDefinedUnitsView
|
|||
* @param platform the platform (language, compiler) for the instruction
|
||||
* @param prototype the instruction's prototype
|
||||
* @param context the initial context for parsing the instruction
|
||||
* @return the new instructions
|
||||
* @throws CodeUnitInsertionException if the instruction cannot be created due to an existing
|
||||
* unit
|
||||
* @param length instruction byte-length (must be in the range 0..prototype.getLength()).
|
||||
* If smaller than the prototype length it must have a value no greater than 7, otherwise
|
||||
* an error will be thrown. A value of 0 or greater-than-or-equal the prototype length
|
||||
* will be ignored and not impose and override length. The length value must be a multiple
|
||||
* of the {@link Language#getInstructionAlignment() instruction alignment} .
|
||||
* @return the newly created instruction.
|
||||
* @throws CodeUnitInsertionException thrown if the new Instruction would overlap and
|
||||
* existing {@link CodeUnit} or the specified {@code length} is unsupported.
|
||||
* @throws IllegalArgumentException if a negative {@code length} is specified.
|
||||
* @throws AddressOverflowException if the instruction would fall off the address space
|
||||
*/
|
||||
protected DBTraceInstruction doCreate(Lifespan lifespan, Address address,
|
||||
InternalTracePlatform platform, InstructionPrototype prototype,
|
||||
ProcessorContextView context)
|
||||
ProcessorContextView context, int length)
|
||||
throws CodeUnitInsertionException, AddressOverflowException {
|
||||
if (platform.getLanguage() != prototype.getLanguage()) {
|
||||
throw new IllegalArgumentException("Platform and prototype disagree in language");
|
||||
}
|
||||
|
||||
Address endAddress = address.addNoWrap(prototype.getLength() - 1);
|
||||
int forcedLengthOverride = InstructionDB.checkLengthOverride(length, prototype);
|
||||
if (length == 0) {
|
||||
length = prototype.getLength();
|
||||
}
|
||||
Address endAddress = address.addNoWrap(length - 1);
|
||||
AddressRangeImpl createdRange = new AddressRangeImpl(address, endAddress);
|
||||
|
||||
// Truncate, then check that against existing code units.
|
||||
|
@ -365,7 +382,7 @@ public class DBTraceInstructionsView extends AbstractBaseDBTraceDefinedUnitsView
|
|||
doSetContext(tasr, prototype.getLanguage(), context);
|
||||
|
||||
DBTraceInstruction created = space.instructionMapSpace.put(tasr, null);
|
||||
created.set(platform, prototype, context);
|
||||
created.set(platform, prototype, context, forcedLengthOverride);
|
||||
|
||||
cacheForContaining.notifyNewEntry(tasr.getLifespan(), createdRange, created);
|
||||
cacheForSequence.notifyNewEntry(tasr.getLifespan(), createdRange, created);
|
||||
|
@ -379,14 +396,14 @@ public class DBTraceInstructionsView extends AbstractBaseDBTraceDefinedUnitsView
|
|||
|
||||
@Override
|
||||
public DBTraceInstruction create(Lifespan lifespan, Address address, TracePlatform platform,
|
||||
InstructionPrototype prototype, ProcessorContextView context)
|
||||
InstructionPrototype prototype, ProcessorContextView context, int forcedLengthOverride)
|
||||
throws CodeUnitInsertionException {
|
||||
InternalTracePlatform dbPlatform = space.manager.platformManager.assertMine(platform);
|
||||
try (LockHold hold = LockHold.lock(space.lock.writeLock())) {
|
||||
DBTraceInstruction created =
|
||||
doCreate(lifespan, address, dbPlatform, prototype, context);
|
||||
space.trace.setChanged(new TraceChangeRecord<>(TraceCodeChangeType.ADDED,
|
||||
space, created, created));
|
||||
doCreate(lifespan, address, dbPlatform, prototype, context, forcedLengthOverride);
|
||||
space.trace.setChanged(
|
||||
new TraceChangeRecord<>(TraceCodeChangeType.ADDED, space, created, created));
|
||||
return created;
|
||||
}
|
||||
catch (AddressOverflowException e) {
|
||||
|
@ -567,9 +584,9 @@ public class DBTraceInstructionsView extends AbstractBaseDBTraceDefinedUnitsView
|
|||
if (lastInstruction != null) {
|
||||
Address maxAddress = DBTraceCodeManager.instructionMax(lastInstruction, true);
|
||||
result.addRange(block.getStartAddress(), maxAddress);
|
||||
space.trace.setChanged(new TraceChangeRecord<>(TraceCodeChangeType.ADDED,
|
||||
space, new ImmutableTraceAddressSnapRange(
|
||||
block.getStartAddress(), maxAddress, lifespan)));
|
||||
space.trace.setChanged(new TraceChangeRecord<>(TraceCodeChangeType.ADDED, space,
|
||||
new ImmutableTraceAddressSnapRange(block.getStartAddress(), maxAddress,
|
||||
lifespan)));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
|
|
@ -708,18 +708,19 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
|
|||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public PropertyMap getPropertyMap(String propertyName) {
|
||||
public PropertyMap<?> getPropertyMap(String propertyName) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instruction createInstruction(Address addr, InstructionPrototype prototype,
|
||||
MemBuffer memBuf, ProcessorContextView context) throws CodeUnitInsertionException {
|
||||
MemBuffer memBuf, ProcessorContextView context, int forcedLengthOverride)
|
||||
throws CodeUnitInsertionException {
|
||||
// TODO: Why memBuf? Can it vary from program memory?
|
||||
return codeOperations.instructions()
|
||||
.create(Lifespan.nowOn(program.snap), addr, platform, prototype, context);
|
||||
.create(Lifespan.nowOn(program.snap), addr, platform, prototype, context,
|
||||
forcedLengthOverride);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -129,6 +129,8 @@ public class DBTraceProgramView implements TraceProgramView {
|
|||
listenFor(TraceDataTypeChangeType.RENAMED, this::dataTypeRenamed);
|
||||
listenFor(TraceDataTypeChangeType.DELETED, this::dataTypeDeleted);
|
||||
|
||||
listenFor(TraceInstructionChangeType.LENGTH_OVERRIDE_CHANGED,
|
||||
this::instructionLengthOverrideChanged);
|
||||
listenFor(TraceInstructionChangeType.FLOW_OVERRIDE_CHANGED,
|
||||
this::instructionFlowOverrideChanged);
|
||||
listenFor(TraceInstructionChangeType.FALL_THROUGH_OVERRIDE_CHANGED,
|
||||
|
@ -466,9 +468,19 @@ public class DBTraceProgramView implements TraceProgramView {
|
|||
return;
|
||||
}
|
||||
queues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_FALLTHROUGH_CHANGED,
|
||||
instruction.getMinAddress(), instruction.getMaxAddress(), null, null, null));
|
||||
instruction.getMinAddress(), instruction.getMinAddress(), null, null, null));
|
||||
}
|
||||
|
||||
private void instructionLengthOverrideChanged(TraceAddressSpace space,
|
||||
TraceInstruction instruction, int oldLengthOverride, int newLengthOverride) {
|
||||
DomainObjectEventQueues queues = isCodeVisible(space, instruction);
|
||||
if (queues == null) {
|
||||
return;
|
||||
}
|
||||
queues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_LENGTH_OVERRIDE_CHANGED,
|
||||
instruction.getMinAddress(), instruction.getMinAddress(), null, null, null));
|
||||
}
|
||||
|
||||
private void memoryBytesChanged(TraceAddressSpace space, TraceAddressSnapRange range,
|
||||
byte[] oldIsNull, byte[] bytes) {
|
||||
DomainObjectEventQueues queues = isBytesVisible(space, range);
|
||||
|
|
|
@ -235,6 +235,8 @@ public interface Trace extends DataTypeManagerDomainObject {
|
|||
new TraceInstructionChangeType<>();
|
||||
public static final TraceInstructionChangeType<Boolean> FALL_THROUGH_OVERRIDE_CHANGED =
|
||||
new TraceInstructionChangeType<>();
|
||||
public static final TraceInstructionChangeType<Integer> LENGTH_OVERRIDE_CHANGED =
|
||||
new TraceInstructionChangeType<>();
|
||||
}
|
||||
|
||||
public static final class TraceMemoryBytesChangeType
|
||||
|
|
|
@ -37,11 +37,12 @@ public interface TraceInstructionsView extends TraceBaseDefinedUnitsView<TraceIn
|
|||
* @param platform the platform
|
||||
* @param prototype the instruction prototype
|
||||
* @param context the input disassembly context for the instruction
|
||||
* @param forcedLengthOverride reduced instruction byte-length (1..7) or 0 to use default length
|
||||
* @return the new instruction
|
||||
* @throws CodeUnitInsertionException if the instruction cannot be created
|
||||
*/
|
||||
TraceInstruction create(Lifespan lifespan, Address address, TracePlatform platform,
|
||||
InstructionPrototype prototype, ProcessorContextView context)
|
||||
InstructionPrototype prototype, ProcessorContextView context, int forcedLengthOverride)
|
||||
throws CodeUnitInsertionException;
|
||||
|
||||
/**
|
||||
|
@ -50,10 +51,10 @@ public interface TraceInstructionsView extends TraceBaseDefinedUnitsView<TraceIn
|
|||
* @see #create(Lifespan, Address, TracePlatform, InstructionPrototype, ProcessorContextView)
|
||||
*/
|
||||
default TraceInstruction create(Lifespan lifespan, Address address,
|
||||
InstructionPrototype prototype, ProcessorContextView context)
|
||||
InstructionPrototype prototype, ProcessorContextView context, int forcedLengthOverride)
|
||||
throws CodeUnitInsertionException {
|
||||
return create(lifespan, address, getTrace().getPlatformManager().getHostPlatform(),
|
||||
prototype, context);
|
||||
prototype, context, forcedLengthOverride);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -564,7 +564,8 @@ public class ToyDBTraceBuilder implements AutoCloseable {
|
|||
InstructionBlock block = dis.pseudoDisassembleBlock(memBuf, defaultContextValue, 1);
|
||||
Instruction pseudoIns = block.iterator().next();
|
||||
return code.instructions()
|
||||
.create(Lifespan.nowOn(snap), start, platform, pseudoIns.getPrototype(), pseudoIns);
|
||||
.create(Lifespan.nowOn(snap), start, platform, pseudoIns.getPrototype(), pseudoIns,
|
||||
0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -468,9 +468,6 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
|
|||
d4008 = b.addData(0, b.addr(0x4008), LongDataType.dataType, b.buf(1, 2, 3, 4));
|
||||
}
|
||||
|
||||
assertTrue(i4004.isSuccessor(i4006));
|
||||
assertFalse(i4004.isSuccessor(d4008));
|
||||
|
||||
assertFalse(i4004.contains(b.addr(0x4003)));
|
||||
assertTrue(i4004.contains(b.addr(0x4004)));
|
||||
assertTrue(i4004.contains(b.addr(0x4005)));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue