GP-1036 EXTERNAL Block Offset-Reference refactor

This commit is contained in:
ghidra1 2022-03-08 05:08:02 -05:00
parent 332480a422
commit 2bced1cd43
43 changed files with 461 additions and 216 deletions

View file

@ -15,7 +15,7 @@
*/
package ghidra.trace.database.program;
import static ghidra.lifecycle.Unfinished.TODO;
import static ghidra.lifecycle.Unfinished.*;
import java.util.*;
import java.util.function.Function;
@ -108,11 +108,10 @@ public abstract class AbstractDBTraceProgramViewReferenceManager implements Refe
}
@Override
public Reference addOffsetMemReference(Address fromAddr, Address toAddr, long offset,
RefType type, SourceType source, int opIndex) {
return refs(true).addOffsetReference(chooseLifespan(fromAddr), fromAddr, toAddr, offset,
type,
source, opIndex);
public Reference addOffsetMemReference(Address fromAddr, Address toAddr, boolean toAddrIsBase,
long offset, RefType type, SourceType source, int opIndex) {
return refs(true).addOffsetReference(chooseLifespan(fromAddr), fromAddr, toAddr,
toAddrIsBase, offset, type, source, opIndex);
}
@Override

View file

@ -20,8 +20,12 @@ import ghidra.trace.database.symbol.DBTraceReferenceSpace.DBTraceReferenceEntry;
import ghidra.trace.model.symbol.TraceOffsetReference;
public class DBTraceOffsetReference extends DBTraceReference implements TraceOffsetReference {
public DBTraceOffsetReference(DBTraceReferenceEntry ent) {
private boolean isExternalBlockReference;
public DBTraceOffsetReference(DBTraceReferenceEntry ent, boolean isExternalBlockReference) {
super(ent);
this.isExternalBlockReference = isExternalBlockReference;
}
@Override
@ -31,6 +35,9 @@ public class DBTraceOffsetReference extends DBTraceReference implements TraceOff
@Override
public Address getBaseAddress() {
if (isExternalBlockReference) {
return ent.toAddress;
}
return ent.toAddress.subtractWrap(ent.ext);
}
}

View file

@ -179,9 +179,10 @@ public class DBTraceReferenceManager extends
@Override
public DBTraceOffsetReference addOffsetReference(Range<Long> lifespan, Address fromAddress,
Address toAddress, long offset, RefType refType, SourceType source, int operandIndex) {
Address toAddress, boolean toAddrIsBase, long offset, RefType refType,
SourceType source, int operandIndex) {
return delegateWrite(fromAddress.getAddressSpace(), s -> s.addOffsetReference(lifespan,
fromAddress, toAddress, offset, refType, source, operandIndex));
fromAddress, toAddress, toAddrIsBase, offset, refType, source, operandIndex));
}
@Override

View file

@ -27,6 +27,7 @@ import db.DBRecord;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.Language;
import ghidra.program.model.lang.Register;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.symbol.*;
import ghidra.trace.database.DBTrace;
import ghidra.trace.database.DBTraceUtils;
@ -41,11 +42,13 @@ import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager.DBTraceSpace
import ghidra.trace.database.space.DBTraceSpaceBased;
import ghidra.trace.model.Trace.TraceReferenceChangeType;
import ghidra.trace.model.Trace.TraceSymbolChangeType;
import ghidra.trace.model.memory.TraceMemoryRegion;
import ghidra.trace.model.symbol.TraceReference;
import ghidra.trace.model.symbol.TraceReferenceSpace;
import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.util.TraceChangeRecord;
import ghidra.util.LockHold;
import ghidra.util.Msg;
import ghidra.util.database.*;
import ghidra.util.database.annot.*;
import ghidra.util.exception.VersionException;
@ -69,7 +72,7 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
OFFSET {
@Override
protected DBTraceReference construct(DBTraceReferenceEntry ent) {
return new DBTraceOffsetReference(ent);
return new DBTraceOffsetReference(ent, false);
}
},
SHIFT {
@ -77,6 +80,12 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
protected DBTraceReference construct(DBTraceReferenceEntry ent) {
return new DBTraceShiftedReference(ent);
}
},
OFFSET_EXTERNAL { // Offset Reference into EXTERNAL memory block region
@Override
protected DBTraceReference construct(DBTraceReferenceEntry ent) {
return new DBTraceOffsetReference(ent, true);
}
};
protected abstract DBTraceReference construct(DBTraceReferenceEntry ent);
@ -411,7 +420,7 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
// TODO: Reference (from, to, opIndex) must be unique!
if (reference.isOffsetReference()) {
OffsetReference oRef = (OffsetReference) reference;
return addOffsetReference(lifespan, oRef.getFromAddress(), oRef.getToAddress(),
return addOffsetReference(lifespan, oRef.getFromAddress(), oRef.getBaseAddress(), true,
oRef.getOffset(), oRef.getReferenceType(), oRef.getSource(),
oRef.getOperandIndex());
}
@ -461,18 +470,61 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
}
}
private boolean isExternalBlockAddress(Range<Long> lifespan, Address addr) {
// TODO: Verify that this works for emulation
TraceMemoryRegion region =
trace.getMemoryManager().getRegionContaining(lifespan.lowerEndpoint(), addr);
return region != null && MemoryBlock.EXTERNAL_BLOCK_NAME.equals(region.getName());
}
@Override
public DBTraceOffsetReference addOffsetReference(Range<Long> lifespan, Address fromAddress,
Address toAddress, long offset, RefType refType, SourceType source, int operandIndex) {
Address toAddress, boolean toAddrIsBase, long offset, RefType refType,
SourceType source, int operandIndex) {
if (operandIndex < -1) {
throw new IllegalArgumentException("operandIndex");
}
try (LockHold hold = LockHold.lock(lock.writeLock())) {
// Handle EXTERNAL Block offset-reference transformation
TypeEnum type = TypeEnum.OFFSET;
boolean isExternalBlockRef = isExternalBlockAddress(lifespan, toAddress);
boolean badOffsetReference = false;
if (isExternalBlockRef) {
type = TypeEnum.OFFSET_EXTERNAL;
if (!toAddrIsBase) {
Address baseAddr = toAddress.subtractWrap(offset);
if (isExternalBlockAddress(lifespan, baseAddr)) {
toAddress = baseAddr;
toAddrIsBase = true;
}
else {
// assume unintentional reference into EXTERNAL block
isExternalBlockRef = false;
type = TypeEnum.OFFSET;
badOffsetReference = true;
}
}
}
else if (toAddrIsBase) {
toAddress = toAddress.addWrap(offset);
toAddrIsBase = false;
if (isExternalBlockAddress(lifespan, toAddress)) {
badOffsetReference = true;
}
}
if (badOffsetReference) {
Msg.warn(this, "Offset Reference from " + fromAddress +
" produces bad Xref into EXTERNAL block");
}
makeWay(lifespan, fromAddress, toAddress, operandIndex);
DBTraceReferenceEntry entry = referenceMapSpace.put(fromAddress, lifespan, null);
entry.set(toAddress, -1, refType, operandIndex, offset, false, TypeEnum.OFFSET, source);
DBTraceOffsetReference ref = new DBTraceOffsetReference(entry);
entry.set(toAddress, -1, refType, operandIndex, offset, false, type, source);
DBTraceOffsetReference ref = new DBTraceOffsetReference(entry, isExternalBlockRef);
entry.ref = ref;
manager.doAddXRef(entry);
return ref;

View file

@ -32,7 +32,8 @@ public interface TraceReferenceOperations {
RefType refType, SourceType source, int operandIndex);
TraceOffsetReference addOffsetReference(Range<Long> lifespan, Address fromAddress,
Address toAddress, long offset, RefType refType, SourceType source, int operandIndex);
Address toAddress, boolean toAddrIsBase, long offset, RefType refType,
SourceType source, int operandIndex);
TraceShiftedReference addShiftedReference(Range<Long> lifespan, Address fromAddress,
Address toAddress, int shift, RefType refType, SourceType source, int operandIndex);

View file

@ -303,9 +303,9 @@ public class ToyDBTraceBuilder implements AutoCloseable {
}
public DBTraceReference addOffsetReference(long creationSnap, Address from, Address to,
long offset) {
boolean toAddrIsBase, long offset) {
return trace.getReferenceManager()
.addOffsetReference(Range.atLeast(creationSnap), from, to,
.addOffsetReference(Range.atLeast(creationSnap), from, to, toAddrIsBase,
offset, RefType.DATA, SourceType.DEFAULT, -1);
}

View file

@ -133,6 +133,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
long offset) {
super(startSnap, fromAddress, toAddress);
this.offset = offset;
// NOTE: intended for test use in the absence of any EXTERNAL memory block concern
this.baseAddress = toAddress.subtract(offset);
}
@ -198,7 +199,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
new DummyTraceShiftedReference(0, b.addr(0x4002), b.addr(0x5002), 1));
}
assertTrue(memRef instanceof DBTraceReference);
assertNotNull(memRef);
assertTrue(offRef instanceof DBTraceOffsetReference);
assertTrue(sftRef instanceof DBTraceShiftedReference);
@ -231,7 +232,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
@Test
public void testAddOffsetReference() {
try (UndoableTransaction tid = b.startTransaction()) {
b.addOffsetReference(0, b.addr(0x4001), b.addr(0x5001), 20);
b.addOffsetReference(0, b.addr(0x4001), b.addr(0x5001), false, 20);
}
DBTraceReferenceSpace space =
manager.getReferenceSpace(b.language.getDefaultDataSpace(), false);
@ -285,7 +286,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
DBTraceReference stkRef;
try (UndoableTransaction tid = b.startTransaction()) {
memRef = b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
offRef = b.addOffsetReference(0, b.addr(0x4001), b.addr(0x5001), 20);
offRef = b.addOffsetReference(0, b.addr(0x4001), b.addr(0x5001), false, 20);
sftRef = b.addShiftedReference(0, b.addr(0x4002), b.addr(0x5002), 1);
regRef = b.addRegisterReference(0, b.addr(0x4003), "r5");
stkRef = b.addStackReference(0, b.addr(0x4004), 0x20);
@ -323,7 +324,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
DBTraceReference stkRef;
try (UndoableTransaction tid = b.startTransaction()) {
memRef = b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000), 3);
offRef = b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), 20);
offRef = b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), false, 20);
sftRef = b.addShiftedReference(0, b.addr(0x4000), b.addr(0x5002), 1);
regRef = b.addRegisterReference(0, b.addr(0x4000), "r5");
stkRef = b.addStackReference(0, b.addr(0x4000), 0x20);
@ -376,7 +377,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
DBTraceReference offRef;
try (UndoableTransaction tid = b.startTransaction()) {
memRef = b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
offRef = b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), 20);
offRef = b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), false, 20);
assertNull(manager.getPrimaryReferenceFrom(0, b.addr(0x4000), -1));
@ -400,7 +401,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
flowRef = manager.addMemoryReference(Range.atLeast(0L), b.addr(0x4000), b.addr(0x4001),
RefType.FLOW, SourceType.DEFAULT, -1);
b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), 20);
b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), false, 20);
}
assertEquals(Set.of(flowRef),
@ -412,7 +413,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
DBTraceReference keptRef;
try (UndoableTransaction tid = b.startTransaction()) {
b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000), 3);
b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), 20);
b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), false, 20);
b.addShiftedReference(0, b.addr(0x4000), b.addr(0x5002), 1);
b.addRegisterReference(0, b.addr(0x4000), "r5");
b.addStackReference(0, b.addr(0x4000), 0x20);
@ -449,7 +450,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
DBTraceReference sftRef;
try (UndoableTransaction tid = b.startTransaction()) {
memRef = b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
offRef = b.addOffsetReference(0, b.addr(0x4001), b.addr(0x5000), 20);
offRef = b.addOffsetReference(0, b.addr(0x4001), b.addr(0x5000), false, 20);
sftRef = b.addShiftedReference(0, b.addr(0x4002), b.addr(0x5000), 1);
b.addRegisterReference(0, b.addr(0x4003), "r5");
b.addStackReference(0, b.addr(0x4004), 0x20);
@ -466,7 +467,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
DBTraceReference keptRef;
try (UndoableTransaction tid = b.startTransaction()) {
b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000), 3);
b.addOffsetReference(0, b.addr(0x4001), b.addr(0x5000), 20);
b.addOffsetReference(0, b.addr(0x4001), b.addr(0x5000), false, 20);
b.addShiftedReference(0, b.addr(0x4002), b.addr(0x5000), 1);
keptRef = b.addMemoryReference(0, b.addr(0x8000), b.addr(0x5001));
}
@ -498,7 +499,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
public void testGetReferenceSourcesAndDestinations() {
try (UndoableTransaction tid = b.startTransaction()) {
b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
b.addOffsetReference(0, b.addr(0x4001), b.addr(0x5001), 20);
b.addOffsetReference(0, b.addr(0x4001), b.addr(0x5001), false, 20);
b.addShiftedReference(0, b.addr(0x4002), b.addr(0x5002), 1);
b.addRegisterReference(0, b.addr(0x4003), "r5");
b.addStackReference(0, b.addr(0x4004), 0x20);
@ -520,7 +521,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
try (UndoableTransaction tid = b.startTransaction()) {
b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), 20);
b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), false, 20);
b.addShiftedReference(0, b.addr(0x4000), b.addr(0x5002), 1);
b.addRegisterReference(0, b.addr(0x4000), "r5");
b.addStackReference(0, b.addr(0x4000), 0x20);
@ -538,7 +539,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
public void testSaveAndLoad() throws CancelledException, IOException, VersionException {
try (UndoableTransaction tid = b.startTransaction()) {
b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), 20);
b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), false, 20);
b.addShiftedReference(0, b.addr(0x4000), b.addr(0x5002), 1);
}
@ -575,7 +576,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
public void testUndo() throws IOException {
try (UndoableTransaction tid = b.startTransaction()) {
b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), 20);
b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), false, 20);
b.addShiftedReference(0, b.addr(0x4000), b.addr(0x5002), 1);
}