mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
GP-1036 EXTERNAL Block Offset-Reference refactor
This commit is contained in:
parent
332480a422
commit
2bced1cd43
43 changed files with 461 additions and 216 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue