Merge remote-tracking branch 'origin/GP-5926_Dan_refsToRange--SQUASHED'

This commit is contained in:
Ryan Kurtz 2025-08-26 05:16:03 -04:00
commit dc1c70e2bf
12 changed files with 539 additions and 163 deletions

View file

@ -24,7 +24,6 @@ import ghidra.program.model.data.TypeDefSettingsDefinition;
import ghidra.program.model.symbol.RefType;
import ghidra.program.model.symbol.SourceType;
import ghidra.trace.database.data.DBTraceDataSettingsOperations;
import ghidra.trace.database.symbol.DBTraceReference;
import ghidra.trace.model.listing.TraceData;
import ghidra.trace.model.symbol.TraceReference;
import ghidra.trace.util.*;
@ -63,7 +62,7 @@ public interface DBTraceDataAdapter extends DBTraceCodeUnitAdapter, DataAdapterM
@Override
default void removeValueReference(Address refAddr) {
try (LockHold hold = getTrace().lockWrite()) {
DBTraceReference ref = getTrace().getReferenceManager()
TraceReference ref = getTrace().getReferenceManager()
.getReference(getStartSnap(),
getAddress(), refAddr, DATA_OP_INDEX);
if (ref == null) {

View file

@ -4,9 +4,9 @@
* 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.
@ -36,8 +36,8 @@ public class DBTraceOffsetReference extends DBTraceReference implements TraceOff
@Override
public Address getBaseAddress() {
if (isExternalBlockReference) {
return ent.toAddress;
return ent.toAddrMin;
}
return ent.toAddress.subtractWrap(ent.ext);
return ent.toAddrMin.subtractWrap(ent.ext);
}
}

View file

@ -19,6 +19,7 @@ import java.util.Collection;
import java.util.Objects;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressRange;
import ghidra.program.model.symbol.*;
import ghidra.trace.database.DBTrace;
import ghidra.trace.database.symbol.DBTraceReferenceSpace.DBTraceReferenceEntry;
@ -76,8 +77,8 @@ public class DBTraceReference implements TraceReference {
}
@Override
public Address getToAddress() {
return ent.toAddress;
public AddressRange getToRange() {
return ent.toRange;
}
@Override

View file

@ -39,6 +39,7 @@ import ghidra.trace.model.symbol.TraceReference;
import ghidra.trace.model.symbol.TraceReferenceManager;
import ghidra.trace.model.thread.TraceThread;
import ghidra.util.UnionAddressSetView;
import ghidra.util.database.spatial.rect.Rectangle2DDirection;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
@ -96,27 +97,27 @@ public class DBTraceReferenceManager extends AbstractDBTraceSpaceBasedManager<DB
}
protected void doAddXRef(DBTraceReferenceEntry entry) {
if (!entry.toAddress.isMemoryAddress()) {
if (!entry.toAddrMin.isMemoryAddress()) {
return;
}
DBTraceReferenceSpace space = getReferenceSpace(entry.toAddress.getAddressSpace(), true);
DBTraceReferenceSpace space = getReferenceSpace(entry.toAddrMin.getAddressSpace(), true);
space.doAddXRef(entry);
}
protected void doDelXRef(DBTraceReferenceEntry entry) {
if (!entry.toAddress.isMemoryAddress()) {
if (!entry.toAddrMin.isMemoryAddress()) {
return;
}
DBTraceReferenceSpace space = getReferenceSpace(entry.toAddress.getAddressSpace(), false);
DBTraceReferenceSpace space = getReferenceSpace(entry.toAddrMin.getAddressSpace(), false);
assert space != null;
space.doDelXRef(entry);
}
protected void doSetXRefLifespan(DBTraceReferenceEntry entry) {
if (!entry.toAddress.isMemoryAddress()) {
if (!entry.toAddrMin.isMemoryAddress()) {
return;
}
DBTraceReferenceSpace space = getReferenceSpace(entry.toAddress.getAddressSpace(), false);
DBTraceReferenceSpace space = getReferenceSpace(entry.toAddrMin.getAddressSpace(), false);
assert space != null;
space.doSetXRefLifespan(entry);
}
@ -164,9 +165,9 @@ public class DBTraceReferenceManager extends AbstractDBTraceSpaceBasedManager<DB
@Override
public DBTraceReference addMemoryReference(Lifespan lifespan, Address fromAddress,
Address toAddress, RefType refType, SourceType source, int operandIndex) {
AddressRange toRange, RefType refType, SourceType source, int operandIndex) {
return delegateWrite(fromAddress.getAddressSpace(), s -> s.addMemoryReference(lifespan,
fromAddress, toAddress, refType, source, operandIndex));
fromAddress, toRange, refType, source, operandIndex));
}
@Override
@ -199,10 +200,10 @@ public class DBTraceReferenceManager extends AbstractDBTraceSpaceBasedManager<DB
}
@Override
public DBTraceReference getReference(long snap, Address fromAddress, Address toAddress,
public DBTraceReference getReference(long snap, Address fromAddress, AddressRange toRange,
int operandIndex) {
return delegateRead(fromAddress.getAddressSpace(),
s -> s.getReference(snap, fromAddress, toAddress, operandIndex));
s -> s.getReference(snap, fromAddress, toRange, operandIndex));
}
@Override
@ -253,9 +254,9 @@ public class DBTraceReferenceManager extends AbstractDBTraceSpaceBasedManager<DB
@Override
public Collection<? extends DBTraceReference> getReferencesToRange(Lifespan span,
AddressRange range) {
return delegateRead(range.getAddressSpace(), s -> s.getReferencesToRange(span, range),
Collections.emptyList());
AddressRange range, Rectangle2DDirection order) {
return delegateRead(range.getAddressSpace(),
s -> s.getReferencesToRange(span, range, order), Collections.emptyList());
}
@Override

View file

@ -42,11 +42,11 @@ import ghidra.trace.model.Lifespan;
import ghidra.trace.model.memory.TraceMemoryRegion;
import ghidra.trace.model.symbol.TraceReference;
import ghidra.trace.model.symbol.TraceReferenceSpace;
import ghidra.trace.util.TraceChangeRecord;
import ghidra.trace.util.TraceEvents;
import ghidra.trace.util.*;
import ghidra.util.*;
import ghidra.util.database.*;
import ghidra.util.database.annot.*;
import ghidra.util.database.spatial.rect.Rectangle2DDirection;
import ghidra.util.exception.VersionException;
public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceSpace {
@ -59,7 +59,7 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
*/
@Override
protected DBTraceReference construct(DBTraceReferenceEntry ent) {
if (ent.toAddress.isStackAddress()) {
if (ent.toAddrMin.isStackAddress()) {
return new DBTraceStackReference(ent);
}
return new DBTraceReference(ent);
@ -97,7 +97,7 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
* <li>0: Initial version and previous unversioned implementation</li>
* </ul>
*/
@DBAnnotatedObjectInfo(version = 1)
@DBAnnotatedObjectInfo(version = 2)
protected static class DBTraceReferenceEntry
extends AbstractDBTraceAddressSnapRangePropertyMapData<DBTraceReferenceEntry>
implements DecodesAddresses {
@ -114,7 +114,8 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
private static final byte TYPE_SHIFT = 5;
//private static final byte TYPE_CLEAR = ~(TYPE_MASK << TYPE_SHIFT);
static final String TO_ADDR_COLUMN_NAME = "ToAddr";
static final String TO_ADDR_MIN_COLUMN_NAME = "ToAddrMin";
static final String TO_ADDR_MAX_COLUMN_NAME = "ToAddrMax";
static final String SYMBOL_ID_COLUMN_NAME = "SymbolId";
static final String REF_TYPE_COLUMN_NAME = "RefType";
static final String OP_INDEX_COLUMN_NAME = "OpIndex";
@ -122,8 +123,10 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
// bit-packed sourceType, isPrimary, type
static final String FLAGS_COLUMN_NAME = "Flags";
@DBAnnotatedColumn(TO_ADDR_COLUMN_NAME)
static DBObjectColumn TO_ADDR_COLUMN;
@DBAnnotatedColumn(TO_ADDR_MIN_COLUMN_NAME)
static DBObjectColumn TO_ADDR_MIN_COLUMN;
@DBAnnotatedColumn(TO_ADDR_MAX_COLUMN_NAME)
static DBObjectColumn TO_ADDR_MAX_COLUMN;
@DBAnnotatedColumn(SYMBOL_ID_COLUMN_NAME)
static DBObjectColumn SYMBOL_ID_COLUMN;
@DBAnnotatedColumn(REF_TYPE_COLUMN_NAME)
@ -140,10 +143,15 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
}
@DBAnnotatedField(
column = TO_ADDR_COLUMN_NAME,
column = TO_ADDR_MIN_COLUMN_NAME,
indexed = true,
codec = AddressDBFieldCodec.class)
protected Address toAddress = Address.NO_ADDRESS;
protected Address toAddrMin = Address.NO_ADDRESS;
@DBAnnotatedField(
column = TO_ADDR_MAX_COLUMN_NAME,
indexed = true,
codec = AddressDBFieldCodec.class)
protected Address toAddrMax = Address.NO_ADDRESS;
@DBAnnotatedField(column = SYMBOL_ID_COLUMN_NAME, indexed = true)
protected long symbolId; // TODO: Is this at the from or to address? I think TO...
@DBAnnotatedField(column = REF_TYPE_COLUMN_NAME, codec = RefTypeDBFieldCodec.class)
@ -157,6 +165,7 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
protected final DBTraceReferenceSpace space;
protected AddressRange toRange;
protected DBTraceReference ref;
public DBTraceReferenceEntry(DBTraceReferenceSpace space,
@ -177,6 +186,7 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
if (created) {
return;
}
toRange = new AddressRangeImpl(toAddrMin, toAddrMax);
TypeEnum type = TypeEnum.values()[(flags >> TYPE_SHIFT) & TYPE_MASK];
ref = type.construct(this);
}
@ -191,17 +201,20 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
return this;
}
protected void set(Address toAddress, long symbolId, RefType refType, int opIndex, long ext,
boolean isPrimary, TypeEnum type, SourceType sourceType) {
this.toAddress = toAddress;
protected void set(AddressRange toRange, long symbolId, RefType refType,
int opIndex, long ext, boolean isPrimary, TypeEnum type, SourceType sourceType) {
this.toAddrMin = toRange.getMinAddress();
this.toAddrMax = toRange.getMaxAddress();
this.symbolId = symbolId;
this.refType = refType;
this.opIndex = (byte) opIndex;
this.ext = ext;
this.flags = (byte) ((isPrimary ? PRIMARY_MASK : 0) |
(sourceType.ordinal() << SOURCE_SHIFT) | type.ordinal() << TYPE_SHIFT);
update(TO_ADDR_COLUMN, SYMBOL_ID_COLUMN, REF_TYPE_COLUMN, OP_INDEX_COLUMN, EXT_COLUMN,
FLAGS_COLUMN);
update(TO_ADDR_MIN_COLUMN, TO_ADDR_MAX_COLUMN, SYMBOL_ID_COLUMN, REF_TYPE_COLUMN,
OP_INDEX_COLUMN, EXT_COLUMN, FLAGS_COLUMN);
this.toRange = toRange;
}
protected void setLifespan(Lifespan lifespan) {
@ -369,7 +382,7 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
protected void doAddXRef(DBTraceReferenceEntry refEnt) {
// Note: called from manager on relevant space
DBTraceXRefEntry xrefEnt = xrefMapSpace.put(refEnt.toAddress, refEnt.getLifespan(), null);
DBTraceXRefEntry xrefEnt = xrefMapSpace.put(refEnt.toRange, refEnt.getLifespan(), null);
xrefEnt.set((short) refEnt.getRange().getAddressSpace().getSpaceID(),
refEnt.getKey());
}
@ -428,40 +441,40 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
return addShiftedReference(lifespan, sRef.getFromAddress(), sRef.getToAddress(),
sRef.getShift(), sRef.getReferenceType(), sRef.getSource(), sRef.getOperandIndex());
}
return addMemoryReference(lifespan, reference.getFromAddress(), reference.getToAddress(),
AddressRange toRange = (reference instanceof TraceReference tref) ? tref.getToRange()
: new AddressRangeImpl(reference.getToAddress(), reference.getToAddress());
return addMemoryReference(lifespan, reference.getFromAddress(), toRange,
reference.getReferenceType(), reference.getSource(), reference.getOperandIndex());
}
protected void makeWay(Lifespan span, Address fromAddress, Address toAddress,
protected void makeWay(Lifespan span, Address fromAddress, AddressRange toRange,
int operandIndex) {
// TODO: Do I consider "compatibility?" as in ReferenceDBManager?
// Do I consider "compatibility?" as in ReferenceDBManager?
// NOTE: Always call with the write lock
for (DBTraceReferenceEntry ent : referenceMapSpace.reduce(
TraceAddressSnapRangeQuery.intersecting(new AddressRangeImpl(fromAddress, fromAddress),
span)).values()) {
if (!ent.toAddress.equals(toAddress)) {
continue;
}
if (ent.opIndex != operandIndex) {
if (!ent.toRange.equals(toRange) ||
ent.opIndex != operandIndex) {
continue;
}
// TODO: This sends events and updates primary. Do I want that here?
// This sends events and updates primary. Do I want that here?
DBTraceUtils.makeWay(ent, span, (e, s) -> e.setLifespan(s), e -> e.ref.delete());
}
}
@Override
public DBTraceReference addMemoryReference(Lifespan lifespan, Address fromAddress,
Address toAddress, RefType refType, SourceType source, int operandIndex) {
AddressRange toRange, RefType refType, SourceType source, int operandIndex) {
if (operandIndex < -1) {
throw new IllegalArgumentException("operandIndex");
}
try (LockHold hold = LockHold.lock(lock.writeLock())) {
makeWay(lifespan, fromAddress, toAddress, operandIndex);
makeWay(lifespan, fromAddress, toRange, operandIndex);
DBTraceReferenceEntry entry = referenceMapSpace.put(fromAddress, lifespan, null);
entry.set(toAddress, -1, refType, operandIndex, 0, false, TypeEnum.MEMORY, source);
entry.set(toRange, -1, refType, operandIndex, 0, false, TypeEnum.MEMORY, source);
DBTraceReference ref = TypeEnum.MEMORY.construct(entry);
entry.ref = ref;
manager.doAddXRef(entry);
@ -520,10 +533,11 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
" produces bad Xref into EXTERNAL block");
}
makeWay(lifespan, fromAddress, toAddress, operandIndex);
AddressRange toRange = new AddressRangeImpl(toAddress, toAddress);
makeWay(lifespan, fromAddress, toRange, operandIndex);
DBTraceReferenceEntry entry = referenceMapSpace.put(fromAddress, lifespan, null);
entry.set(toAddress, -1, refType, operandIndex, offset, false, type, source);
entry.set(toRange, -1, refType, operandIndex, offset, false, type, source);
DBTraceOffsetReference ref = new DBTraceOffsetReference(entry, isExternalBlockRef);
entry.ref = ref;
manager.doAddXRef(entry);
@ -538,10 +552,11 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
throw new IllegalArgumentException("operandIndex");
}
try (LockHold hold = LockHold.lock(lock.writeLock())) {
makeWay(lifespan, fromAddress, toAddress, operandIndex);
AddressRange toRange = new AddressRangeImpl(toAddress, toAddress);
makeWay(lifespan, fromAddress, toRange, operandIndex);
DBTraceReferenceEntry entry = referenceMapSpace.put(fromAddress, lifespan, null);
entry.set(toAddress, -1, refType, operandIndex, shift, false, TypeEnum.SHIFT, source);
entry.set(toRange, -1, refType, operandIndex, shift, false, TypeEnum.SHIFT, source);
DBTraceShiftedReference ref = new DBTraceShiftedReference(entry);
entry.ref = ref;
manager.doAddXRef(entry);
@ -552,8 +567,8 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
@Override
public DBTraceReference addRegisterReference(Lifespan lifespan, Address fromAddress,
Register toRegister, RefType refType, SourceType source, int operandIndex) {
return addMemoryReference(lifespan, fromAddress, toRegister.getAddress(), refType, source,
operandIndex);
return addMemoryReference(lifespan, fromAddress,
TraceRegisterUtils.rangeForRegister(toRegister), refType, source, operandIndex);
}
@Override
@ -561,20 +576,19 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
int toStackOffset, RefType refType, SourceType source, int operandIndex) {
// TODO: base and guest compiler specs, too?
AddressSpace stack = baseLanguage.getDefaultCompilerSpec().getStackSpace();
return addMemoryReference(lifespan, fromAddress, stack.getAddress(toStackOffset), refType,
source, operandIndex);
Address toAddress = stack.getAddress(toStackOffset);
AddressRange toRange = new AddressRangeImpl(toAddress, toAddress);
return addMemoryReference(lifespan, fromAddress, toRange, refType, source, operandIndex);
}
@Override
public DBTraceReference getReference(long snap, Address fromAddress, Address toAddress,
public DBTraceReference getReference(long snap, Address fromAddress, AddressRange toRange,
int operandIndex) {
try (LockHold hold = LockHold.lock(lock.readLock())) {
for (DBTraceReferenceEntry entry : referenceMapSpace.reduce(
TraceAddressSnapRangeQuery.at(fromAddress, snap)).values()) {
if (!toAddress.equals(entry.toAddress)) {
continue;
}
if (entry.opIndex != operandIndex) {
if (!entry.toRange.equals(toRange) ||
entry.opIndex != operandIndex) {
continue;
}
return entry.ref;
@ -667,9 +681,10 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
@Override
public Collection<? extends DBTraceReference> getReferencesToRange(Lifespan span,
AddressRange range) {
AddressRange range, Rectangle2DDirection order) {
return new LazyCollection<>(
() -> xrefMapSpace.reduce(TraceAddressSnapRangeQuery.intersecting(range, span))
() -> xrefMapSpace
.reduce(TraceAddressSnapRangeQuery.intersecting(range, span).starting(order))
.values()
.stream()
.map(this::getRefForXRefEntry));

View file

@ -4,9 +4,9 @@
* 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.
@ -30,6 +30,6 @@ public class DBTraceShiftedReference extends DBTraceReference implements TraceSh
@Override
public long getValue() {
return ent.toAddress.getOffset() >> ent.ext;
return ent.toAddrMin.getOffset() >> ent.ext;
}
}

View file

@ -4,9 +4,9 @@
* 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.
@ -15,6 +15,7 @@
*/
package ghidra.trace.model.symbol;
import ghidra.program.model.address.Address;
import ghidra.program.model.symbol.OffsetReference;
public interface TraceOffsetReference extends TraceReference, OffsetReference {
@ -22,4 +23,9 @@ public interface TraceOffsetReference extends TraceReference, OffsetReference {
default boolean isOffsetReference() {
return true;
}
@Override
default Address getToAddress() {
return TraceReference.super.getToAddress();
}
}

View file

@ -4,9 +4,9 @@
* 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.
@ -15,17 +15,69 @@
*/
package ghidra.trace.model.symbol;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressRange;
import ghidra.program.model.symbol.*;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.Trace;
/**
* A {@link Reference} within a {@link Trace}
*/
public interface TraceReference extends Reference {
/**
* Get the trace containing this reference
*
* @return the trace
*/
Trace getTrace();
/**
* Get the lifespan for which this reference is effective
*
* @return the lifespan
*/
Lifespan getLifespan();
/**
* Get the starting snapshot key of this reference's lifespan
*
* @return the starting snapshot
* @see #getLifespan()
*/
long getStartSnap();
/**
* Get the "to" range of this reference.
*
* <p>
* Because references are often used in traces to indicate <em>actual</em> run-time writes, it
* is not sufficient to examine the code unit at a single "to" address and assume the reference
* is to the entire unit. For one, the read might be of a specific field in a structure data
* unit. For two, a read of a large unit may be implemented as a loop of several smaller reads.
* The trace could (and probably should) record each atomic read. In theory, one could examine
* the "from" instruction and operand index to derive the length, but that is onerous and not
* indexed. So instead, we record the exact "to" range in each reference and index it. This
* allows for easy implementation of, e.g., access breakpoints.
*
* @return the to range
*/
AddressRange getToRange();
/**
* {@inheritDoc}
*
* <p>
* For a trace reference, the "to" part is actually a range. This returns the minimum address of
* that range.
*
* @see #getToRange()
*/
@Override
default Address getToAddress() {
return getToRange().getMinAddress();
}
/**
* Make this reference primary.
*
@ -43,10 +95,27 @@ public interface TraceReference extends Reference {
*/
void setReferenceType(RefType refType);
/**
* Set the symbol associated with this reference
*
* @param symbol the symbol
* @see #getSymbolID()
*/
void setAssociatedSymbol(Symbol symbol);
/**
* Clear the associated symbol
*
* @see #getSymbolID()
*/
void clearAssociatedSymbol();
/**
* Get the symbol associated with this reference
*
* @return the symbol
* @see #getSymbolID()
*/
default Symbol getAssociatedSymbol() {
long id = getSymbolID();
return id == -1 ? null : getTrace().getSymbolManager().getSymbolByID(id);
@ -115,5 +184,8 @@ public interface TraceReference extends Reference {
return 0;
}
/**
* Delete this reference
*/
void delete();
}

View file

@ -4,9 +4,9 @@
* 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.
@ -21,93 +21,355 @@ import ghidra.program.model.address.*;
import ghidra.program.model.lang.Register;
import ghidra.program.model.symbol.*;
import ghidra.trace.model.Lifespan;
import ghidra.util.database.spatial.rect.Rectangle2DDirection;
/**
* The operations for adding and retrieving references
*/
public interface TraceReferenceOperations {
/**
* A (a copy of) the given reference to this manager
*
* @param reference the reference to add
* @return the resulting reference
*/
TraceReference addReference(TraceReference reference);
/**
* A (a copy of) the given reference to this manager
*
* @param lifespan the span of time where this reference applies
* @param reference the reference
* @return the resulting reference
*/
TraceReference addReference(Lifespan lifespan, Reference reference);
TraceReference addMemoryReference(Lifespan lifespan, Address fromAddress, Address toAddress,
/**
* Add a memory reference
*
* @param lifespan the span of time where this reference applies
* @param fromAddress the from address of the reference
* @param toRange the to addresses of the reference
* @param refType the type of reference
* @param source how this reference was derived
* @param operandIndex the operand index for the "from" end, or -1
* @return the resulting reference
*/
TraceReference addMemoryReference(Lifespan lifespan, Address fromAddress, AddressRange toRange,
RefType refType, SourceType source, int operandIndex);
/**
* Add a memory reference
*
* @param lifespan the span of time where this reference applies
* @param fromAddress the from address of the reference
* @param toAddress the to address of the reference
* @param refType the type of reference
* @param source how this reference was derived
* @param operandIndex the operand index for the "from" end, or -1
* @return the resulting reference
*/
default TraceReference addMemoryReference(Lifespan lifespan, Address fromAddress,
Address toAddress, RefType refType, SourceType source, int operandIndex) {
return addMemoryReference(lifespan, fromAddress, new AddressRangeImpl(toAddress, toAddress),
refType, source, operandIndex);
}
/**
* Add an offset memory reference
*
* @param lifespan the span of time where this reference applies
* @param fromAddress the from address of the reference
* @param toAddress the to address of the reference
* @param toAddrIsBase indicate whether or not toAddress incorporates the offset. False means
* toAddress=base+offset. True means toAddress=base.
* @param offset value added to the base address
* @param refType the type of reference
* @param source how this reference was derived
* @param operandIndex the operand index for the "from" end, or -1
* @return the resulting reference
*/
TraceOffsetReference addOffsetReference(Lifespan lifespan, Address fromAddress,
Address toAddress, boolean toAddrIsBase, long offset, RefType refType,
SourceType source, int operandIndex);
/**
* Add a shifted memory reference
*
* @param lifespan the span of time where this reference applies
* @param fromAddress the from address of the reference
* @param toAddress the to address of the reference
* @param shift the number of bits to shift left
* @param refType the type of reference
* @param source how this reference was derived
* @param operandIndex the operand index for the "from" end, or -1
* @return the resulting reference
*/
TraceShiftedReference addShiftedReference(Lifespan lifespan, Address fromAddress,
Address toAddress, int shift, RefType refType, SourceType source, int operandIndex);
/**
* Add a register reference
*
* @param lifespan the span of time where this reference applies
* @param fromAddress the from address of the reference
* @param toRegister the to register of the reference
* @param refType the type of reference
* @param source how this reference was derived
* @param operandIndex the operand index for the "from" end, or -1
* @return the resulting reference
*/
TraceReference addRegisterReference(Lifespan lifespan, Address fromAddress,
Register toRegister, RefType refType, SourceType source, int operandIndex);
/**
* Add a (static) stack reference
*
* @param lifespan the span of time where this reference applies
* @param fromAddress the from address of the reference
* @param toStackOffset the to offset of the reference
* @param refType the type of reference
* @param source how this reference was derived
* @param operandIndex the operand index for the "from" end, or -1
* @return the resulting reference
*/
TraceReference addStackReference(Lifespan lifespan, Address fromAddress, int toStackOffset,
RefType refType, SourceType source, int operandIndex);
TraceReference getReference(long snap, Address fromAddress, Address toAddress,
/**
* Find the reference that matches the given parameters
*
* <p>
* <b>NOTE:</b> It is not sufficient to <em>intersect</em> the to range. It must exactly match
* that given.
*
* @param snap the snapshot key
* @param fromAddress the from address
* @param toRange the to address range
* @param operandIndex the operand index for the "from" end, or -1
* @return the found reference or null
*/
TraceReference getReference(long snap, Address fromAddress, AddressRange toRange,
int operandIndex);
/**
* Find the reference that matches the given parameters
*
* <p>
* <b>NOTE:</b> It is not sufficient to <em>contain</em> the to address. To to range must be a
* singleton and exactly match that given. To match a range, see
* {@link #getReference(long, Address, AddressRange, int)}
*
* @param snap the snapshot key
* @param fromAddress the from address
* @param toAddress the to address
* @param operandIndex the operand index for the "from" end, or -1
* @return the found reference or null
*/
default TraceReference getReference(long snap, Address fromAddress, Address toAddress,
int operandIndex) {
return getReference(snap, fromAddress, new AddressRangeImpl(toAddress, toAddress),
operandIndex);
}
/**
* Find all references from the given snapshot and address
*
* @param snap the snapshot key
* @param fromAddress the from address
* @return the collection of results
*/
Collection<? extends TraceReference> getReferencesFrom(long snap, Address fromAddress);
/**
* Find all references from the given snapshot, address, and operand index
*
* @param snap the snapshot key
* @param fromAddress the from address
* @param operandIndex the operand index for the "from" end, or -1
* @return the collection of results
*/
Collection<? extends TraceReference> getReferencesFrom(long snap, Address fromAddress,
int operandIndex);
/**
* TODO: Document me
* Find all references with from addresses contained in the given lifespan and address range
*
* This returns all references from addresses within the given range, regardless of operand
* index.
*
* @param span
* @param range
* @return
* @param span the lifespan to examine
* @param range the range to examine
* @return the collection of results
*/
Collection<? extends TraceReference> getReferencesFromRange(Lifespan span,
AddressRange range);
/**
* Get the primary reference matching from the given snapshot, address, and operand index
*
* @param snap the snapshot key
* @param fromAddress the from address
* @param operandIndex the operand index for the "from" end, or -1
* @return the found reference or null
*/
TraceReference getPrimaryReferenceFrom(long snap, Address fromAddress, int operandIndex);
/**
* Get all flow references from the given snapshot and address
*
* @param snap the snapshot key
* @param fromAddress the from address
* @return the collection of results
*/
Collection<? extends TraceReference> getFlowReferencesFrom(long snap, Address fromAddress);
/**
* Clear all references from the given lifespan and address range
*
* <p>
* Any reference intersecting the given "from" parameters will have its lifespan truncated to
* the start of the given lifespan.
*
* @param span the lifespan to remove
* @param range the range to clear
*/
void clearReferencesFrom(Lifespan span, AddressRange range);
/**
* Get all references whose to address (or range) contains the given snapshot and address
*
* @param snap the snapshot key
* @param toAddress the to address
* @return the collection of results
*/
Collection<? extends TraceReference> getReferencesTo(long snap, Address toAddress);
/**
* Clear all references to the given lifespan and address range
*
* <p>
* Any reference intersecting the given "to" parameters will have its lifespan truncated to the
* start of the given lifespan.
*
* @param span the lifespan to remove
* @param range the range of clear
*/
void clearReferencesTo(Lifespan span, AddressRange range);
/**
* TODO: Document me
* Get all references whose to address range intersects the given lifespan and address range
*
* This returns all references to addresses within the given range, regardless of operand index.
* <p>
* The following iteration orders may be specified for the resulting (lazy) collection:
*
* @param span
* @param range
* @return
* <ul>
* <li>{@code null} - no particular order. This spares the cost of sorting.</li>
* <li>{@link Rectangle2DDirection#TOPMOST} - most-recent (latest snapshot) first.</li>
* <li>{@link Rectangle2DDirection#BOTTOMMOST} - least-recent (earliest including scratch
* snapshot first).</li>
* <li>{@link Rectangle2DDirection#LEFTMOST} - smallest address first.</li>
* <li>{@link Rectangle2DDirection#RIGHTMOST} - largest address first.</li>
* </ul>
*
* <p>
* "Secondary" sorting is not supported.
*
* @param span the lifespan to examine
* @param range the range to examine
* @param order the order of items in the collection.
* @return the collection of results
*/
Collection<? extends TraceReference> getReferencesToRange(Lifespan span, AddressRange range);
Collection<? extends TraceReference> getReferencesToRange(Lifespan span, AddressRange range,
Rectangle2DDirection order);
// TODO: Support Variable references
/**
* Get all references whose to address range intersects the given lifespan and address range
*
* @param span the lifespan to examine
* @param range the range to examine
* @return the collection of results
*/
default Collection<? extends TraceReference> getReferencesToRange(Lifespan span,
AddressRange range) {
return getReferencesToRange(span, range, null);
}
// NOTE: Variable references are not (yet?) supported
/**
* Check if there exists a reference from the given snapshot and address
*
* @param snap the snapshot key
* @param fromAddress the from address
* @return true if one or more references exist
*/
default boolean hasReferencesFrom(long snap, Address fromAddress) {
return !getReferencesFrom(snap, fromAddress).isEmpty();
}
/**
* Check if there exists a reference from the given snapshot, address, and operand
*
* @param snap the snapshot key
* @param fromAddress the from address
* @param operandIndex the operand index, or -1
* @return true if one or more references exist
*/
default boolean hasReferencesFrom(long snap, Address fromAddress, int operandIndex) {
return !getReferencesFrom(snap, fromAddress, operandIndex).isEmpty();
}
/**
* Check if there exists a flow reference from the given snapshot and address
*
* @param snap the snapshot key
* @param fromAddress the from address
* @return true if one or more flow references exist
*/
default boolean hasFlowReferencesFrom(long snap, Address fromAddress) {
return !getFlowReferencesFrom(snap, fromAddress).isEmpty();
}
/**
* Check if there exists a reference to the given snapshot and address
*
* @param snap the snapshot key
* @param toAddress the to address
* @return true if one or more references exists
*/
default boolean hasReferencesTo(long snap, Address toAddress) {
return !getReferencesTo(snap, toAddress).isEmpty();
}
/**
* Get an address set of all "from" addresses in any reference intersecting the given lifespan
*
* @param span the lifespan to examine
* @return a (lazily-computed) address set view of all "from" addresses
*/
AddressSetView getReferenceSources(Lifespan span);
/**
* Get an address set of all "to" addresses in any reference intersecting the given lifespan
*
* @param span the lifespan to examine
* @return a (lazily-computed) address set view of all "to" addresses
*/
AddressSetView getReferenceDestinations(Lifespan span);
/**
* Count the number of references from the given snapshot and address
*
* @param snap the snapshot key
* @param fromAddress the from address
* @return the number of references
*/
int getReferenceCountFrom(long snap, Address fromAddress);
/**
* Count the number of references to the given snapshot and address
*
* @param snap the snapshot key
* @param toAddress the to address
* @return the number of references
*/
int getReferenceCountTo(long snap, Address toAddress);
}

View file

@ -837,7 +837,7 @@ public class ToyDBTraceBuilder implements AutoCloseable {
* @param to the to address
* @return the reference
*/
public DBTraceReference addMemoryReference(long creationSnap, Address from, Address to) {
public DBTraceReference addMemoryReference(long creationSnap, Address from, AddressRange to) {
return addMemoryReference(creationSnap, from, to, -1);
}
@ -850,7 +850,7 @@ public class ToyDBTraceBuilder implements AutoCloseable {
* @param operandIndex the operand index, or -1 for mnemonic
* @return the reference
*/
public DBTraceReference addMemoryReference(long creationSnap, Address from, Address to,
public DBTraceReference addMemoryReference(long creationSnap, Address from, AddressRange to,
int operandIndex) {
return trace.getReferenceManager()
.addMemoryReference(Lifespan.nowOn(creationSnap), from, to, RefType.DATA,

View file

@ -38,7 +38,6 @@ import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.database.listing.DBTraceCommentAdapter.DBTraceCommentEntry;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
import ghidra.trace.database.memory.DBTraceMemorySpace;
import ghidra.trace.database.symbol.DBTraceReference;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.guest.TraceGuestPlatform;
import ghidra.trace.model.listing.TraceData;
@ -52,7 +51,6 @@ import ghidra.trace.model.target.schema.XmlSchemaContext;
import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.util.TraceRegisterUtils;
import ghidra.util.*;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.NoValueException;
import ghidra.util.map.TypeMismatchException;
@ -620,7 +618,7 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest {
assertEquals(Set.of(mnemRef, opRef, stackRef, regRef), set(i4004.getReferencesFrom()));
DBTraceReference refTo;
TraceReference refTo;
try (Transaction tx = b.startTransaction()) {
refTo = b.trace.getReferenceManager()
.addMemoryReference(Lifespan.ALL, b.addr(0x3000), b.addr(0x4004),

View file

@ -4,9 +4,9 @@
* 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.
@ -19,19 +19,20 @@ import static org.junit.Assert.*;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.Collection;
import java.util.Set;
import org.junit.*;
import db.Transaction;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.address.*;
import ghidra.program.model.symbol.*;
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.Trace;
import ghidra.trace.model.symbol.*;
import ghidra.trace.util.TraceRegisterUtils;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
@ -39,12 +40,12 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
protected static class DummyTraceReference implements TraceReference {
protected final Lifespan lifespan;
protected final Address fromAddress;
protected final Address toAddress;
protected final AddressRange toRange;
public DummyTraceReference(long startSnap, Address fromAddress, Address toAddress) {
public DummyTraceReference(long startSnap, Address fromAddress, AddressRange toRange) {
this.lifespan = Lifespan.nowOn(startSnap);
this.fromAddress = fromAddress;
this.toAddress = toAddress;
this.toRange = toRange;
}
@Override
@ -53,8 +54,8 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
}
@Override
public Address getToAddress() {
return toAddress;
public AddressRange getToRange() {
return toRange;
}
@Override
@ -130,7 +131,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
public DummyTraceOffsetReference(long startSnap, Address fromAddress, Address toAddress,
long offset) {
super(startSnap, fromAddress, toAddress);
super(startSnap, fromAddress, new AddressRangeImpl(toAddress, toAddress));
this.offset = offset;
// NOTE: intended for test use in the absence of any EXTERNAL memory block concern
this.baseAddress = toAddress.subtract(offset);
@ -154,7 +155,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
public DummyTraceShiftedReference(long startSnap, Address fromAddress, Address toAddress,
int shift) {
super(startSnap, fromAddress, toAddress);
super(startSnap, fromAddress, new AddressRangeImpl(toAddress, toAddress));
this.shift = shift;
this.value = toAddress.getOffset() >>> shift;
}
@ -190,8 +191,8 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
DBTraceReference offRef;
DBTraceReference sftRef;
try (Transaction tx = b.startTransaction()) {
memRef =
manager.addReference(new DummyTraceReference(0, b.addr(0x4000), b.addr(0x5000)));
memRef = manager.addReference(
new DummyTraceReference(0, b.addr(0x4000), b.range(0x5000, 0x5003)));
offRef = manager.addReference(
new DummyTraceOffsetReference(0, b.addr(0x4001), b.addr(0x5001), 20));
sftRef = manager.addReference(
@ -203,6 +204,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
assertTrue(sftRef instanceof DBTraceShiftedReference);
assertEquals(b.addr(0x4000), memRef.getFromAddress());
assertEquals(b.range(0x5000, 0x5003), memRef.getToRange());
assertEquals(b.addr(0x5000), memRef.getToAddress());
assertEquals(b.addr(0x4001), offRef.getFromAddress());
@ -219,7 +221,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
@Test
public void testAddMemoryReference() {
try (Transaction tx = b.startTransaction()) {
b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
b.addMemoryReference(0, b.addr(0x4000), b.range(0x5000, 0x5003));
}
DBTraceReferenceSpace space =
manager.getReferenceSpace(b.language.getDefaultDataSpace(), false);
@ -284,7 +286,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
DBTraceReference regRef;
DBTraceReference stkRef;
try (Transaction tx = b.startTransaction()) {
memRef = b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
memRef = b.addMemoryReference(0, b.addr(0x4000), b.range(0x5000, 0x5003));
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");
@ -292,20 +294,21 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
}
assertNull(manager.getReference(0, b.addr(0x4000), b.addr(0x5000), 0));
assertNull(manager.getReference(0, b.addr(0x4000), b.range(0x5000, 0x5003), 0));
assertNull(manager.getReference(0, b.addr(0x4000), b.addr(0x5001), -1));
assertNull(manager.getReference(0, b.addr(0x4001), b.addr(0x5000), -1));
assertNull(manager.getReference(-1, b.addr(0x4000), b.addr(0x5000), -1));
assertEquals(memRef, manager.getReference(0, b.addr(0x4000), b.addr(0x5000), -1));
assertEquals(memRef, manager.getReference(10, b.addr(0x4000), b.addr(0x5000), -1));
assertEquals(memRef, manager.getReference(0, b.addr(0x4000), b.range(0x5000, 0x5003), -1));
assertEquals(memRef, manager.getReference(10, b.addr(0x4000), b.range(0x5000, 0x5003), -1));
assertEquals(offRef, manager.getReference(0, b.addr(0x4001), b.addr(0x5001), -1));
assertEquals(sftRef, manager.getReference(0, b.addr(0x4002), b.addr(0x5002), -1));
assertEquals(regRef,
manager.getReference(0, b.addr(0x4003), b.language.getRegister("r5").getAddress(), -1));
assertNull(
manager.getReference(0, b.addr(0x4003), b.language.getRegister("r6").getAddress(), -1));
assertEquals(regRef, manager.getReference(0, b.addr(0x4003),
TraceRegisterUtils.rangeForRegister(b.language.getRegister("r5")), -1));
assertNull(manager.getReference(0, b.addr(0x4003),
TraceRegisterUtils.rangeForRegister(b.language.getRegister("r6")), -1));
// TODO: A better way to manage the compiler spec
assertEquals(stkRef, manager.getReference(0, b.addr(0x4004),
@ -322,21 +325,21 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
DBTraceReference regRef;
DBTraceReference stkRef;
try (Transaction tx = b.startTransaction()) {
memRef = b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000), 3);
memRef = b.addMemoryReference(0, b.addr(0x4000), b.range(0x5000, 0x5003), 3);
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);
b.addMemoryReference(0, b.addr(0x4001), b.addr(0x8000));
b.addMemoryReference(0, b.addr(0x4001), b.range(0x8000, 0x8003));
}
assertEquals(Set.of(memRef, offRef, sftRef, regRef, stkRef),
new HashSet<>(manager.getReferencesFrom(0, b.addr(0x4000))));
Set.copyOf(manager.getReferencesFrom(0, b.addr(0x4000))));
assertEquals(Set.of(memRef),
new HashSet<>(manager.getReferencesFrom(0, b.addr(0x4000), 3)));
Set.copyOf(manager.getReferencesFrom(0, b.addr(0x4000), 3)));
assertEquals(Set.of(offRef, sftRef, regRef, stkRef),
new HashSet<>(manager.getReferencesFrom(0, b.addr(0x4000), -1)));
Set.copyOf(manager.getReferencesFrom(0, b.addr(0x4000), -1)));
}
@Test
@ -347,23 +350,23 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
DBTraceReference diffTo;
DBTraceReference diffOpIndex;
try (Transaction tx = b.startTransaction()) {
at0 = b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000), 0);
b.addMemoryReference(15, b.addr(0x4000), b.addr(0x5000), 0); // Lost
at10 = b.addMemoryReference(10, b.addr(0x4000), b.addr(0x5000), 0);
at0 = b.addMemoryReference(0, b.addr(0x4000), b.range(0x5000, 0x5003), 0);
b.addMemoryReference(15, b.addr(0x4000), b.range(0x5000, 0x5003), 0); // Lost
at10 = b.addMemoryReference(10, b.addr(0x4000), b.range(0x5000, 0x5003), 0);
diffFrom = b.addMemoryReference(0, b.addr(0x4001), b.addr(0x5000), 0);
diffTo = b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5001), 0);
diffOpIndex = b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000), 1);
diffFrom = b.addMemoryReference(0, b.addr(0x4001), b.range(0x5000, 0x5003), 0);
diffTo = b.addMemoryReference(0, b.addr(0x4000), b.range(0x5004, 0x5007), 0);
diffOpIndex = b.addMemoryReference(0, b.addr(0x4000), b.range(0x5000, 0x5003), 1);
assertEquals(Set.of(at0, diffTo, diffOpIndex),
new HashSet<>(manager.getReferencesFrom(0, b.addr(0x4000))));
Set.copyOf(manager.getReferencesFrom(0, b.addr(0x4000))));
assertEquals(Set.of(at10, diffTo, diffOpIndex),
new HashSet<>(manager.getReferencesFrom(15, b.addr(0x4000))));
Set.copyOf(manager.getReferencesFrom(15, b.addr(0x4000))));
assertEquals(Set.of(diffFrom),
new HashSet<>(manager.getReferencesFrom(0, b.addr(0x4001))));
Set.copyOf(manager.getReferencesFrom(0, b.addr(0x4001))));
assertEquals(Set.of(diffFrom),
new HashSet<>(manager.getReferencesFrom(15, b.addr(0x4001))));
Set.copyOf(manager.getReferencesFrom(15, b.addr(0x4001))));
}
}
@ -375,7 +378,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
DBTraceReference memRef;
DBTraceReference offRef;
try (Transaction tx = b.startTransaction()) {
memRef = b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
memRef = b.addMemoryReference(0, b.addr(0x4000), b.range(0x5000, 0x5003));
offRef = b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), false, 20);
assertNull(manager.getPrimaryReferenceFrom(0, b.addr(0x4000), -1));
@ -395,28 +398,28 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
@Test
public void testGetFlowReferencesFrom() {
DBTraceReference flowRef;
TraceReference flowRef;
try (Transaction tx = b.startTransaction()) {
flowRef = manager.addMemoryReference(Lifespan.nowOn(0), b.addr(0x4000), b.addr(0x4001),
RefType.FLOW, SourceType.DEFAULT, -1);
b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
b.addMemoryReference(0, b.addr(0x4000), b.range(0x5000, 0x5003));
b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), false, 20);
}
assertEquals(Set.of(flowRef),
new HashSet<>(manager.getFlowReferencesFrom(0, b.addr(0x4000))));
Set.copyOf(manager.getFlowReferencesFrom(0, b.addr(0x4000))));
}
@Test
public void testClearReferencesFrom() {
DBTraceReference keptRef;
try (Transaction tx = b.startTransaction()) {
b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000), 3);
b.addMemoryReference(0, b.addr(0x4000), b.range(0x5000, 0x5003), 3);
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);
keptRef = b.addMemoryReference(0, b.addr(0x4001), b.addr(0x8000));
keptRef = b.addMemoryReference(0, b.addr(0x4001), b.range(0x8000, 0x8003));
}
assertEquals(5, manager.getReferencesFrom(0, b.addr(0x4000)).size());
@ -448,27 +451,46 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
DBTraceReference offRef;
DBTraceReference sftRef;
try (Transaction tx = b.startTransaction()) {
memRef = b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
memRef = b.addMemoryReference(0, b.addr(0x4000), b.range(0x5000, 0x5003));
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);
b.addMemoryReference(0, b.addr(0x4005), b.addr(0x8000));
b.addMemoryReference(0, b.addr(0x4005), b.range(0x8000, 0x8003));
}
assertEquals(Set.of(memRef, offRef, sftRef),
new HashSet<>(manager.getReferencesTo(0, b.addr(0x5000))));
Set.copyOf(manager.getReferencesTo(0, b.addr(0x5000))));
}
@Test
public void tesGetReferencesToRange() {
DBTraceReference memRef1;
DBTraceReference memRef2;
DBTraceReference memRef3;
try (Transaction tx = b.startTransaction()) {
memRef1 = b.addMemoryReference(0, b.addr(0x4000), b.range(0x5000, 0x5003));
memRef2 = b.addMemoryReference(5, b.addr(0x4000), b.range(0x5002, 0x5005));
memRef3 = b.addMemoryReference(0, b.addr(0x4000), b.range(0x5004, 0x5007));
}
assertEquals(Set.of(memRef1, memRef2, memRef3),
Set.copyOf(manager.getReferencesToRange(Lifespan.nowOn(0), b.range(0x5000, 0x5007))));
assertEquals(Set.of(memRef1),
Set.copyOf(manager.getReferencesToRange(Lifespan.nowOn(0), b.range(0x5000, 0x5000))));
assertEquals(Set.of(memRef1, memRef3),
Set.copyOf(manager.getReferencesToRange(Lifespan.at(0), b.range(0x5000, 0x5007))));
}
@Test
public void testClearReferencesTo() {
DBTraceReference keptRef;
try (Transaction tx = b.startTransaction()) {
b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000), 3);
b.addMemoryReference(0, b.addr(0x4000), b.range(0x5000, 0x5003), 3);
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));
keptRef = b.addMemoryReference(0, b.addr(0x8000), b.range(0x5004, 0x5007));
}
assertEquals(3, manager.getReferencesTo(0, b.addr(0x5000)).size());
@ -489,26 +511,26 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
assertEquals(0, manager.getReferencesTo(0, b.addr(0x5000)).size());
assertEquals(0, manager.getReferencesTo(-1, b.addr(0x5000)).size());
assertEquals(1, manager.getReferencesTo(0, b.addr(0x5001)).size());
assertEquals(keptRef, manager.getReferencesTo(0, b.addr(0x5001)).iterator().next());
assertEquals(1, manager.getReferencesTo(0, b.addr(0x5004)).size());
assertEquals(keptRef, manager.getReferencesTo(0, b.addr(0x5004)).iterator().next());
assertEquals(Lifespan.nowOn(0), keptRef.getLifespan());
}
@Test
public void testGetReferenceSourcesAndDestinations() {
try (Transaction tx = b.startTransaction()) {
b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
b.addMemoryReference(0, b.addr(0x4000), b.range(0x5000, 0x5000));
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);
b.addMemoryReference(0, b.addr(0x4005), b.addr(0x8000));
b.addMemoryReference(0, b.addr(0x4005), b.range(0x8000, 0x8003));
}
assertEquals(b.set(b.range(0x4000, 0x4005)),
manager.getReferenceSources(Lifespan.span(0, 0)));
assertEquals(b.set(), manager.getReferenceSources(Lifespan.span(-1, -1)));
assertEquals(b.set(b.range(0x5000, 0x5002), b.range(0x8000, 0x8000)),
assertEquals(b.set(b.range(0x5000, 0x5002), b.range(0x8000, 0x8003)),
manager.getReferenceDestinations(Lifespan.span(0, 0)));
assertEquals(b.set(), manager.getReferenceDestinations(Lifespan.span(-1, -1)));
}
@ -519,13 +541,13 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
assertEquals(0, manager.getReferenceCountTo(0, b.addr(0x5000)));
try (Transaction tx = b.startTransaction()) {
b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
b.addMemoryReference(0, b.addr(0x4000), b.range(0x5000, 0x5003));
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);
b.addMemoryReference(0, b.addr(0x4001), b.addr(0x5000));
b.addMemoryReference(0, b.addr(0x4002), b.addr(0x5000));
b.addMemoryReference(0, b.addr(0x4001), b.range(0x5000, 0x5003));
b.addMemoryReference(0, b.addr(0x4002), b.range(0x5000, 0x5003));
}
assertEquals(5, manager.getReferenceCountFrom(0, b.addr(0x4000)));
@ -537,7 +559,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
@Test
public void testSaveAndLoad() throws CancelledException, IOException, VersionException {
try (Transaction tx = b.startTransaction()) {
b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
b.addMemoryReference(0, b.addr(0x4000), b.range(0x5000, 0x5003));
b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), false, 20);
b.addShiftedReference(0, b.addr(0x4000), b.addr(0x5002), 1);
}
@ -553,9 +575,9 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
manager.getReferencesFrom(0, b.addr(0x4000));
assertEquals(3, refs.size());
DBTraceReference ref;
TraceReference ref;
ref = manager.getReference(0, b.addr(0x4000), b.addr(0x5000), -1);
ref = manager.getReference(0, b.addr(0x4000), b.range(0x5000, 0x5003), -1);
assertEquals(DBTraceReference.class, ref.getClass());
assertEquals(RefType.DATA, ref.getReferenceType());
assertEquals(SourceType.DEFAULT, ref.getSource());
@ -574,7 +596,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
@Test
public void testUndo() throws IOException {
try (Transaction tx = b.startTransaction()) {
b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
b.addMemoryReference(0, b.addr(0x4000), b.range(0x5000, 0x5003));
b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), false, 20);
b.addShiftedReference(0, b.addr(0x4000), b.addr(0x5002), 1);
}
@ -597,9 +619,9 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
.createOverlayAddressSpace("test",
b.trace.getBaseAddressFactory().getDefaultAddressSpace());
b.addMemoryReference(0, os.getAddress(0x4000), os.getAddress(0x5000));
b.addMemoryReference(0, os.getAddress(0x4001), b.addr(0x5001));
b.addMemoryReference(0, b.addr(0x4002), os.getAddress(0x5002));
b.addMemoryReference(0, os.getAddress(0x4000), b.range(os, 0x5000, 0x5003));
b.addMemoryReference(0, os.getAddress(0x4001), b.range(0x5004, 0x5007));
b.addMemoryReference(0, b.addr(0x4002), b.range(os, 0x5008, 0x500b));
}
File saved = b.save();
@ -613,19 +635,19 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
AddressSpace os = b.trace.getBaseAddressFactory().getAddressSpace("test");
assertNotNull(os);
DBTraceReference ref;
TraceReference ref;
ref = manager.getReference(0, os.getAddress(0x4000), os.getAddress(0x5000), -1);
ref = manager.getReference(0, os.getAddress(0x4000), b.range(os, 0x5000, 0x5003), -1);
assertNotNull(ref);
assertEquals(os, ref.getFromAddress().getAddressSpace());
assertEquals(os, ref.getToAddress().getAddressSpace());
ref = manager.getReference(0, os.getAddress(0x4001), b.addr(0x5001), -1);
ref = manager.getReference(0, os.getAddress(0x4001), b.range(0x5004, 0x5007), -1);
assertNotNull(ref);
assertEquals(os, ref.getFromAddress().getAddressSpace());
assertEquals(ds, ref.getToAddress().getAddressSpace());
ref = manager.getReference(0, b.addr(0x4002), os.getAddress(0x5002), -1);
ref = manager.getReference(0, b.addr(0x4002), b.range(os, 0x5008, 0x500b), -1);
assertNotNull(ref);
assertEquals(ds, ref.getFromAddress().getAddressSpace());
assertEquals(os, ref.getToAddress().getAddressSpace());
@ -636,11 +658,11 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
assertEquals(0, manager.getReferenceCountFrom(0, os.getAddress(0x4002)));
assertEquals(1, manager.getReferenceCountFrom(0, b.addr(0x4002)));
assertEquals(0, manager.getReferenceCountTo(0, os.getAddress(0x5001)));
assertEquals(1, manager.getReferenceCountTo(0, b.addr(0x5001)));
assertEquals(0, manager.getReferenceCountTo(0, os.getAddress(0x5004)));
assertEquals(1, manager.getReferenceCountTo(0, b.addr(0x5004)));
assertEquals(0, manager.getReferenceCountTo(0, b.addr(0x5002)));
assertEquals(1, manager.getReferenceCountTo(0, os.getAddress(0x5002)));
assertEquals(0, manager.getReferenceCountTo(0, b.addr(0x5008)));
assertEquals(1, manager.getReferenceCountTo(0, os.getAddress(0x5008)));
}
}
}