diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceDataAdapter.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceDataAdapter.java index e0420c4b28..7079caee82 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceDataAdapter.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceDataAdapter.java @@ -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) { diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceOffsetReference.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceOffsetReference.java index 632f0fe9e2..cb2a6ffe74 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceOffsetReference.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceOffsetReference.java @@ -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); } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReference.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReference.java index e1dbedcfe6..9721951860 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReference.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReference.java @@ -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 diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceManager.java index b8e3ba34fc..85f8199aa3 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceManager.java @@ -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 s.addMemoryReference(lifespan, - fromAddress, toAddress, refType, source, operandIndex)); + fromAddress, toRange, refType, source, operandIndex)); } @Override @@ -199,10 +200,10 @@ public class DBTraceReferenceManager extends AbstractDBTraceSpaceBasedManager s.getReference(snap, fromAddress, toAddress, operandIndex)); + s -> s.getReference(snap, fromAddress, toRange, operandIndex)); } @Override @@ -253,9 +254,9 @@ public class DBTraceReferenceManager extends AbstractDBTraceSpaceBasedManager 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 diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java index c15b7f94b4..cdb57199de 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java @@ -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 *
  • 0: Initial version and previous unversioned implementation
  • * */ - @DBAnnotatedObjectInfo(version = 1) + @DBAnnotatedObjectInfo(version = 2) protected static class DBTraceReferenceEntry extends AbstractDBTraceAddressSnapRangePropertyMapData 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 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)); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceShiftedReference.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceShiftedReference.java index d818383d29..36a0061d44 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceShiftedReference.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceShiftedReference.java @@ -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; } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceOffsetReference.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceOffsetReference.java index 9062778244..d810b4c465 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceOffsetReference.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceOffsetReference.java @@ -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(); + } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceReference.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceReference.java index 2d51d84fb7..7de23f5d71 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceReference.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceReference.java @@ -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. + * + *

    + * Because references are often used in traces to indicate actual 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} + * + *

    + * 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(); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceReferenceOperations.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceReferenceOperations.java index 428b3e3167..e902575151 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceReferenceOperations.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceReferenceOperations.java @@ -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 + * + *

    + * NOTE: It is not sufficient to intersect 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 + * + *

    + * NOTE: It is not sufficient to contain 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 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 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 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 getFlowReferencesFrom(long snap, Address fromAddress); + /** + * Clear all references from the given lifespan and address range + * + *

    + * 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 getReferencesTo(long snap, Address toAddress); + /** + * Clear all references to the given lifespan and address range + * + *

    + * 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. + *

    + * The following iteration orders may be specified for the resulting (lazy) collection: * - * @param span - * @param range - * @return + *

      + *
    • {@code null} - no particular order. This spares the cost of sorting.
    • + *
    • {@link Rectangle2DDirection#TOPMOST} - most-recent (latest snapshot) first.
    • + *
    • {@link Rectangle2DDirection#BOTTOMMOST} - least-recent (earliest including scratch + * snapshot first).
    • + *
    • {@link Rectangle2DDirection#LEFTMOST} - smallest address first.
    • + *
    • {@link Rectangle2DDirection#RIGHTMOST} - largest address first.
    • + *
    + * + *

    + * "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 getReferencesToRange(Lifespan span, AddressRange range); + Collection 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 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); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java index b705fcb04d..90652d07f9 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java @@ -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, diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/listing/DBTraceCodeUnitTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/listing/DBTraceCodeUnitTest.java index 8d29c3091c..5c17fe7dda 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/listing/DBTraceCodeUnitTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/listing/DBTraceCodeUnitTest.java @@ -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), diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/symbol/DBTraceReferenceManagerTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/symbol/DBTraceReferenceManagerTest.java index 979bed8d14..2876db5f65 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/symbol/DBTraceReferenceManagerTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/symbol/DBTraceReferenceManagerTest.java @@ -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))); } } }