mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Merge remote-tracking branch 'origin/GP-2191_Dan_makePublicTraceAddressPropertyManager--SQUASHED'
This commit is contained in:
commit
4ef111155a
16 changed files with 713 additions and 119 deletions
|
@ -55,6 +55,7 @@ import ghidra.trace.database.time.DBTraceTimeManager;
|
|||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.memory.TraceMemoryRegion;
|
||||
import ghidra.trace.model.program.TraceProgramView;
|
||||
import ghidra.trace.model.property.TraceAddressPropertyManager;
|
||||
import ghidra.trace.util.TraceChangeManager;
|
||||
import ghidra.trace.util.TraceChangeRecord;
|
||||
import ghidra.util.*;
|
||||
|
@ -456,8 +457,13 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
|||
return baseAddressFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceAddressPropertyManager getAddressPropertyManager() {
|
||||
return addressPropertyManager.getApiPropertyManager();
|
||||
}
|
||||
|
||||
@Internal
|
||||
public DBTraceAddressPropertyManager getAddressPropertyManager() {
|
||||
public DBTraceAddressPropertyManager getInternalAddressPropertyManager() {
|
||||
return addressPropertyManager;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,9 +33,9 @@ import ghidra.program.model.symbol.*;
|
|||
import ghidra.trace.database.DBTrace;
|
||||
import ghidra.trace.database.symbol.DBTraceReference;
|
||||
import ghidra.trace.model.listing.TraceCodeUnit;
|
||||
import ghidra.trace.model.map.TracePropertyMap;
|
||||
import ghidra.trace.model.memory.TraceMemoryRegion;
|
||||
import ghidra.trace.model.program.TraceProgramView;
|
||||
import ghidra.trace.model.property.*;
|
||||
import ghidra.trace.model.symbol.TraceReference;
|
||||
import ghidra.trace.model.symbol.TraceSymbol;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
|
@ -84,8 +84,9 @@ public interface DBTraceCodeUnitAdapter extends TraceCodeUnit, MemBufferAdapter
|
|||
@Override
|
||||
default <T> void setProperty(String name, Class<T> valueClass, T value) {
|
||||
try (LockHold hold = LockHold.lock(getTrace().getReadWriteLock().writeLock())) {
|
||||
TracePropertyMap<? super T> setter =
|
||||
getTrace().getAddressPropertyManager().getOrCreatePropertySetter(name, valueClass);
|
||||
TracePropertySetter<T> setter =
|
||||
getTrace().getInternalAddressPropertyManager()
|
||||
.getOrCreatePropertySetter(name, valueClass);
|
||||
setter.set(getLifespan(), getAddress(), value);
|
||||
}
|
||||
}
|
||||
|
@ -121,8 +122,8 @@ public interface DBTraceCodeUnitAdapter extends TraceCodeUnit, MemBufferAdapter
|
|||
@Override
|
||||
default <T> T getProperty(String name, Class<T> valueClass) {
|
||||
try (LockHold hold = LockHold.lock(getTrace().getReadWriteLock().readLock())) {
|
||||
TracePropertyMap<? extends T> getter =
|
||||
getTrace().getAddressPropertyManager().getPropertyGetter(name, valueClass);
|
||||
TracePropertyGetter<T> getter =
|
||||
getTrace().getInternalAddressPropertyManager().getPropertyGetter(name, valueClass);
|
||||
return getter.get(getStartSnap(), getAddress());
|
||||
}
|
||||
}
|
||||
|
@ -149,13 +150,13 @@ public interface DBTraceCodeUnitAdapter extends TraceCodeUnit, MemBufferAdapter
|
|||
@Override
|
||||
default boolean hasProperty(String name) {
|
||||
try (LockHold hold = LockHold.lock(getTrace().getReadWriteLock().readLock())) {
|
||||
TracePropertyMap<?> map = getTrace().getAddressPropertyManager().getPropertyMap(name);
|
||||
TracePropertyMap<?> map =
|
||||
getTrace().getInternalAddressPropertyManager().getPropertyMap(name);
|
||||
if (map == null) {
|
||||
return false;
|
||||
}
|
||||
// NOTE: Properties all defined at start snap
|
||||
return map.getAddressSetView(Range.closed(getStartSnap(), getStartSnap()))
|
||||
.contains(getAddress());
|
||||
return map.getAddressSetView(Range.singleton(getStartSnap())).contains(getAddress());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,29 +164,28 @@ public interface DBTraceCodeUnitAdapter extends TraceCodeUnit, MemBufferAdapter
|
|||
default boolean getVoidProperty(String name) {
|
||||
// NOTE: Nearly identical to hasProperty, except named property must be Void type
|
||||
try (LockHold hold = LockHold.lock(getTrace().getReadWriteLock().readLock())) {
|
||||
TracePropertyMap<? extends Void> getter =
|
||||
getTrace().getAddressPropertyManager().getPropertyGetter(name, Void.class);
|
||||
TracePropertyGetter<Void> getter =
|
||||
getTrace().getInternalAddressPropertyManager().getPropertyGetter(name, Void.class);
|
||||
if (getter == null) {
|
||||
return false;
|
||||
}
|
||||
return getter.getAddressSetView(Range.closed(getStartSnap(), getStartSnap()))
|
||||
.contains(
|
||||
getAddress());
|
||||
return getter.getAddressSetView(Range.singleton(getStartSnap())).contains(getAddress());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
default Iterator<String> propertyNames() {
|
||||
Range<Long> closed = Range.closed(getStartSnap(), getStartSnap());
|
||||
Range<Long> span = Range.singleton(getStartSnap());
|
||||
return Iterators.transform(Iterators.filter(
|
||||
getTrace().getAddressPropertyManager().getAllProperties().entrySet().iterator(),
|
||||
e -> e.getValue().getAddressSetView(closed).contains(getAddress())), Entry::getKey);
|
||||
getTrace().getInternalAddressPropertyManager().getAllProperties().entrySet().iterator(),
|
||||
e -> e.getValue().getAddressSetView(span).contains(getAddress())), Entry::getKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void removeProperty(String name) {
|
||||
try (LockHold hold = LockHold.lock(getTrace().getReadWriteLock().writeLock())) {
|
||||
TracePropertyMap<?> map = getTrace().getAddressPropertyManager().getPropertyMap(name);
|
||||
TracePropertyMap<?> map =
|
||||
getTrace().getInternalAddressPropertyManager().getPropertyMap(name);
|
||||
if (map == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -197,14 +197,12 @@ public interface DBTraceCodeUnitAdapter extends TraceCodeUnit, MemBufferAdapter
|
|||
default void visitProperty(PropertyVisitor visitor, String propertyName) {
|
||||
try (LockHold hold = LockHold.lock(getTrace().getReadWriteLock().readLock())) {
|
||||
TracePropertyMap<?> map =
|
||||
getTrace().getAddressPropertyManager().getPropertyMap(propertyName);
|
||||
getTrace().getInternalAddressPropertyManager().getPropertyMap(propertyName);
|
||||
if (map == null) {
|
||||
return;
|
||||
}
|
||||
if (map.getValueClass() == Void.class) {
|
||||
if (map.getAddressSetView(Range.closed(getStartSnap(), getStartSnap()))
|
||||
.contains(
|
||||
getAddress())) {
|
||||
if (map.getAddressSetView(Range.singleton(getStartSnap())).contains(getAddress())) {
|
||||
visitor.visit();
|
||||
}
|
||||
return;
|
||||
|
@ -437,5 +435,4 @@ public interface DBTraceCodeUnitAdapter extends TraceCodeUnit, MemBufferAdapter
|
|||
throw new MemoryAccessException("Couldn't get requested bytes for CodeUnit");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.Abstract
|
|||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
|
||||
import ghidra.trace.database.thread.DBTraceThreadManager;
|
||||
import ghidra.trace.model.TraceAddressSnapRange;
|
||||
import ghidra.trace.model.map.TracePropertyMap;
|
||||
import ghidra.trace.model.property.TracePropertyMap;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.database.*;
|
||||
import ghidra.util.database.DBCachedObjectStoreFactory.AbstractDBFieldCodec;
|
||||
|
@ -71,11 +71,21 @@ public abstract class AbstractDBTracePropertyMap<T, DR extends AbstractDBTraceAd
|
|||
put(address, lifespan, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Range<Long> lifespan, AddressRange range, T value) {
|
||||
put(range, lifespan, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(long snap, Address address) {
|
||||
return reduce(TraceAddressSnapRangeQuery.at(address, snap)).firstValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<TraceAddressSnapRange, T> getEntry(long snap, Address address) {
|
||||
return reduce(TraceAddressSnapRangeQuery.at(address, snap)).firstEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear(Range<Long> span, AddressRange range) {
|
||||
try (LockHold hold = LockHold.lock(lock.writeLock())) {
|
||||
|
@ -88,7 +98,6 @@ public abstract class AbstractDBTracePropertyMap<T, DR extends AbstractDBTraceAd
|
|||
|
||||
@Override
|
||||
public T put(TraceAddressSnapRange shape, T value) {
|
||||
assert shape.getRange().getLength() == 1;
|
||||
try (LockHold hold = LockHold.lock(lock.writeLock())) {
|
||||
for (Entry<TraceAddressSnapRange, T> entry : reduce(
|
||||
TraceAddressSnapRangeQuery.intersecting(shape)).entries()) {
|
||||
|
|
|
@ -43,10 +43,10 @@ import ghidra.trace.database.symbol.DBTraceFunctionSymbol;
|
|||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.*;
|
||||
import ghidra.trace.model.listing.*;
|
||||
import ghidra.trace.model.map.TracePropertyMap;
|
||||
import ghidra.trace.model.memory.TraceMemoryRegion;
|
||||
import ghidra.trace.model.program.TraceProgramView;
|
||||
import ghidra.trace.model.program.TraceProgramViewListing;
|
||||
import ghidra.trace.model.property.TracePropertyMap;
|
||||
import ghidra.trace.model.symbol.TraceFunctionSymbol;
|
||||
import ghidra.trace.util.*;
|
||||
import ghidra.util.*;
|
||||
|
@ -358,7 +358,7 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
|
|||
|
||||
// TODO: Cover this in testing
|
||||
TracePropertyMap<?> map =
|
||||
program.trace.getAddressPropertyManager().getPropertyMap(property);
|
||||
program.trace.getInternalAddressPropertyManager().getPropertyMap(property);
|
||||
if (map == null) {
|
||||
return new WrappingCodeUnitIterator(Collections.emptyIterator());
|
||||
}
|
||||
|
@ -380,7 +380,7 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
|
|||
|
||||
// TODO: Cover this in testing
|
||||
TracePropertyMap<?> map =
|
||||
program.trace.getAddressPropertyManager().getPropertyMap(property);
|
||||
program.trace.getInternalAddressPropertyManager().getPropertyMap(property);
|
||||
if (map == null) {
|
||||
return new WrappingCodeUnitIterator(Collections.emptyIterator());
|
||||
}
|
||||
|
@ -403,7 +403,7 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
|
|||
|
||||
// TODO: Cover this in testing
|
||||
TracePropertyMap<?> map =
|
||||
program.trace.getAddressPropertyManager().getPropertyMap(property);
|
||||
program.trace.getInternalAddressPropertyManager().getPropertyMap(property);
|
||||
if (map == null) {
|
||||
return new WrappingCodeUnitIterator(Collections.emptyIterator());
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
package ghidra.trace.database.property;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
|
||||
import db.DBHandle;
|
||||
|
@ -29,8 +30,7 @@ import ghidra.trace.database.DBTraceManager;
|
|||
import ghidra.trace.database.map.AbstractDBTracePropertyMap;
|
||||
import ghidra.trace.database.map.AbstractDBTracePropertyMap.*;
|
||||
import ghidra.trace.database.thread.DBTraceThreadManager;
|
||||
import ghidra.trace.model.map.TracePropertyMap;
|
||||
import ghidra.trace.model.property.TraceAddressPropertyManager;
|
||||
import ghidra.trace.model.property.*;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.database.*;
|
||||
import ghidra.util.database.annot.*;
|
||||
|
@ -90,8 +90,9 @@ public class DBTraceAddressPropertyManager implements TraceAddressPropertyManage
|
|||
protected final DBCachedObjectStore<DBTraceAddressPropertyEntry> propertyStore;
|
||||
protected final Map<String, AbstractDBTracePropertyMap<?, ?>> propertyMapsByName =
|
||||
new HashMap<>();
|
||||
protected final Map<String, TracePropertyMap<?>> propertyMapsView =
|
||||
Collections.unmodifiableMap(propertyMapsByName);
|
||||
|
||||
protected final TraceAddressPropertyManager apiView =
|
||||
new DBTraceAddressPropertyManagerApiView(this);
|
||||
|
||||
public DBTraceAddressPropertyManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock,
|
||||
TaskMonitor monitor, Language baseLanguage, DBTrace trace,
|
||||
|
@ -215,7 +216,7 @@ public class DBTraceAddressPropertyManager implements TraceAddressPropertyManage
|
|||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> TracePropertyMap<? extends T> getPropertyGetter(String name, Class<T> valueClass) {
|
||||
public <T> TracePropertyGetter<T> getPropertyGetter(String name, Class<T> valueClass) {
|
||||
try (LockHold hold = LockHold.lock(lock.readLock())) {
|
||||
AbstractDBTracePropertyMap<?, ?> map = propertyMapsByName.get(name);
|
||||
if (map == null) {
|
||||
|
@ -225,19 +226,18 @@ public class DBTraceAddressPropertyManager implements TraceAddressPropertyManage
|
|||
throw new TypeMismatchException("Property " + name + " has type " +
|
||||
map.getValueClass() + ", which does not extend " + valueClass);
|
||||
}
|
||||
return (TracePropertyMap<? extends T>) map;
|
||||
return (TracePropertyGetter<T>) map;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> TracePropertyMap<? super T> getOrCreatePropertySetter(String name,
|
||||
public <T> TracePropertySetter<T> getOrCreatePropertySetter(String name,
|
||||
Class<T> valueClass) {
|
||||
try (LockHold hold = LockHold.lock(lock.writeLock())) {
|
||||
AbstractDBTracePropertyMap<?, ?> map = propertyMapsByName.get(name);
|
||||
if (map == null) {
|
||||
try {
|
||||
// TODO: This is not ideal
|
||||
return createPropertyMap(name, valueClass);
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
|
@ -261,7 +261,9 @@ public class DBTraceAddressPropertyManager implements TraceAddressPropertyManage
|
|||
|
||||
@Override
|
||||
public Map<String, TracePropertyMap<?>> getAllProperties() {
|
||||
return propertyMapsView;
|
||||
try (LockHold hold = LockHold.lock(lock.readLock())) {
|
||||
return Map.copyOf(propertyMapsByName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -277,4 +279,8 @@ public class DBTraceAddressPropertyManager implements TraceAddressPropertyManage
|
|||
loadPropertyMaps(TaskMonitor.DUMMY);
|
||||
}
|
||||
}
|
||||
|
||||
public TraceAddressPropertyManager getApiPropertyManager() {
|
||||
return apiView;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* 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.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.trace.database.property;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ghidra.trace.model.property.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
class DBTraceAddressPropertyManagerApiView implements TraceAddressPropertyManager {
|
||||
protected static final String API_PREFIX = "_API_";
|
||||
|
||||
protected final DBTraceAddressPropertyManager internalView;
|
||||
|
||||
public DBTraceAddressPropertyManagerApiView(DBTraceAddressPropertyManager internalView) {
|
||||
this.internalView = internalView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> TracePropertyMap<T> createPropertyMap(String name, Class<T> valueClass)
|
||||
throws DuplicateNameException {
|
||||
return internalView.createPropertyMap(API_PREFIX + name, valueClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> TracePropertyMap<T> getPropertyMap(String name, Class<T> valueClass) {
|
||||
return internalView.getPropertyMap(API_PREFIX + name, valueClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> TracePropertyMap<T> getOrCreatePropertyMap(String name, Class<T> valueClass) {
|
||||
return internalView.getOrCreatePropertyMap(API_PREFIX + name, valueClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> TracePropertyGetter<T> getPropertyGetter(String name,
|
||||
Class<T> valueClass) {
|
||||
return internalView.getPropertyGetter(API_PREFIX + name, valueClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> TracePropertySetter<T> getOrCreatePropertySetter(String name,
|
||||
Class<T> valueClass) {
|
||||
return internalView.getOrCreatePropertySetter(API_PREFIX + name, valueClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TracePropertyMap<?> getPropertyMap(String name) {
|
||||
return internalView.getPropertyMap(API_PREFIX + name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, TracePropertyMap<?>> getAllProperties() {
|
||||
return internalView.getAllProperties()
|
||||
.entrySet()
|
||||
.stream()
|
||||
.filter(e -> e.getKey().startsWith(API_PREFIX))
|
||||
.collect(Collectors.toMap(e -> e.getKey().substring(API_PREFIX.length()),
|
||||
Entry::getValue));
|
||||
}
|
||||
}
|
|
@ -38,6 +38,7 @@ import ghidra.trace.model.memory.*;
|
|||
import ghidra.trace.model.modules.*;
|
||||
import ghidra.trace.model.program.TraceProgramView;
|
||||
import ghidra.trace.model.program.TraceVariableSnapProgramView;
|
||||
import ghidra.trace.model.property.TraceAddressPropertyManager;
|
||||
import ghidra.trace.model.stack.TraceStack;
|
||||
import ghidra.trace.model.stack.TraceStackManager;
|
||||
import ghidra.trace.model.symbol.*;
|
||||
|
@ -388,6 +389,8 @@ public interface Trace extends DataTypeManagerDomainObject {
|
|||
|
||||
AddressFactory getBaseAddressFactory();
|
||||
|
||||
TraceAddressPropertyManager getAddressPropertyManager();
|
||||
|
||||
TraceBookmarkManager getBookmarkManager();
|
||||
|
||||
TraceBreakpointManager getBreakpointManager();
|
||||
|
|
|
@ -20,7 +20,7 @@ import java.util.Map;
|
|||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.trace.model.map.UnsignedUtils;
|
||||
import ghidra.util.NumericUtilities;
|
||||
import ghidra.util.database.spatial.rect.EuclideanSpace2D;
|
||||
import utilities.util.IDHashed;
|
||||
|
||||
|
@ -65,10 +65,10 @@ public class TraceAddressSnapSpace implements EuclideanSpace2D<Address, Long> {
|
|||
@Override
|
||||
public double distX(Address x1, Address x2) {
|
||||
if (x2.compareTo(x1) > 0) {
|
||||
return UnsignedUtils.unsignedLongToDouble(x2.subtract(x1));
|
||||
return NumericUtilities.unsignedLongToDouble(x2.subtract(x1));
|
||||
}
|
||||
else {
|
||||
return UnsignedUtils.unsignedLongToDouble(x1.subtract(x2));
|
||||
return NumericUtilities.unsignedLongToDouble(x1.subtract(x2));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* 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.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.trace.model.map;
|
||||
|
||||
import com.google.common.primitives.UnsignedLong;
|
||||
|
||||
public enum UnsignedUtils {
|
||||
;
|
||||
/**
|
||||
* Equivalent to {@link UnsignedLong#doubleValue()}, but without the overhead of instantiating
|
||||
* one.
|
||||
*
|
||||
* @param val the long to treat as unsigned and convert
|
||||
* @return the double
|
||||
*/
|
||||
public static double unsignedLongToDouble(long val) {
|
||||
double dVal = val & 0x7FFF_FFFF_FFFF_FFFFL;
|
||||
if (val < 0) {
|
||||
dVal += 0x1.0p63;
|
||||
}
|
||||
return dVal;
|
||||
}
|
||||
}
|
|
@ -17,17 +17,30 @@ package ghidra.trace.model.property;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.util.TypeMismatchException;
|
||||
import ghidra.trace.model.map.TracePropertyMap;
|
||||
import ghidra.util.Saveable;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public interface TraceAddressPropertyManager {
|
||||
/**
|
||||
* Create a property map with the given name having the given type
|
||||
*
|
||||
* <p>
|
||||
* The following types are supported for valueClass:
|
||||
* <ul>
|
||||
* <li>{@link Integer}</li>
|
||||
* <li>{@link Long}</li>
|
||||
* <li>{@link String}</li>
|
||||
* <li>{@link Void}: presence or absence of entry satisfies "boolean" use case</li>
|
||||
* <li>{@code ? extends }{@link Saveable}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* Note that for maps of user-defined {@link Saveable} type, only the specified type is accepted
|
||||
* by the map. Attempting to save an extension of that type may lead to undefined behavior,
|
||||
* esp., if it attempts to save additional fields. When the value is restored, it will have the
|
||||
* type given in {@code valueClass}, not the extended type.
|
||||
*
|
||||
* @param name the name
|
||||
* @param valueClass the type of values
|
||||
* @return the new property map
|
||||
|
@ -49,6 +62,7 @@ public interface TraceAddressPropertyManager {
|
|||
/**
|
||||
* Get the property map with the given name, creating it if necessary, of the given type
|
||||
*
|
||||
* @see #createPropertyMap(String, Class)
|
||||
* @param name the name
|
||||
* @param valueClass the expected type of values
|
||||
* @return the (possibly new) property map
|
||||
|
@ -58,38 +72,30 @@ public interface TraceAddressPropertyManager {
|
|||
/**
|
||||
* Get the property map with the given name, if its type extends the given type
|
||||
*
|
||||
* This implies that the returned map's {@link TracePropertyMap#get(long, Address)} method will
|
||||
* return values which can be assigned to variables of the given type. Its
|
||||
* {@link TracePropertyMap#set(Range, Address, Object)} method, however, will not accept any
|
||||
* value parameter, as it will have a wildcard-extends type.
|
||||
*
|
||||
* @param name the name
|
||||
* @param valueClass the expected type of values to get
|
||||
* @return the property map suitable for getting values of the given type
|
||||
*/
|
||||
<T> TracePropertyMap<? extends T> getPropertyGetter(String name, Class<T> valueClass);
|
||||
<T> TracePropertyGetter<T> getPropertyGetter(String name, Class<T> valueClass);
|
||||
|
||||
/**
|
||||
* Get the property map with the given name, if its type is a super-type of the given type
|
||||
*
|
||||
* This implies that the returned map's {@link TracePropertyMap#set(Range, Address, Object)}
|
||||
* method will accept values from variables of the given type. Its
|
||||
* {@link TracePropertyMap#get(long, Address)} method, however, will return {@link Object}, as
|
||||
* it will have a wildcard-super type.
|
||||
*
|
||||
*
|
||||
* @see #createPropertyMap(String, Class)
|
||||
* @param name the name
|
||||
* @param valueClass the expect3ed type of values to set
|
||||
* @param valueClass the expected type of values to set
|
||||
* @return the property map suitable for setting values of the given type
|
||||
*/
|
||||
<T> TracePropertyMap<? super T> getOrCreatePropertySetter(String name, Class<T> valueClass);
|
||||
<T> TracePropertySetter<T> getOrCreatePropertySetter(String name, Class<T> valueClass);
|
||||
|
||||
/**
|
||||
* Get the property map with the given name.
|
||||
*
|
||||
* Note that no type checking is performed (there is no {@code valueClass} parameter, after all.
|
||||
* Thus, the returned map is suitable only for clearing and querying where the property is
|
||||
* present. The caller may perform run-time type checking via the
|
||||
* {@link TracePropertyMap#getValueClass()} method.
|
||||
* <p>
|
||||
* Note that no type checking is performed (there is no {@code valueClass} parameter). Thus, the
|
||||
* returned map is suitable only for clearing and querying where the property is present. The
|
||||
* caller may perform run-time type checking via the {@link TracePropertyMap#getValueClass()}
|
||||
* method.
|
||||
*
|
||||
* @param name the name
|
||||
* @return the property map
|
||||
|
@ -97,9 +103,9 @@ public interface TraceAddressPropertyManager {
|
|||
TracePropertyMap<?> getPropertyMap(String name);
|
||||
|
||||
/**
|
||||
* Get an unmodifiable view of all the defined properties
|
||||
* Get a copy of all the defined properties
|
||||
*
|
||||
* @return the map view of names to property maps
|
||||
* @return the set of names
|
||||
*/
|
||||
Map<String, TracePropertyMap<?>> getAllProperties();
|
||||
}
|
||||
|
|
|
@ -13,20 +13,35 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.trace.model.map;
|
||||
package ghidra.trace.model.property;
|
||||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
|
||||
public interface TracePropertyMap<T> {
|
||||
Class<T> getValueClass();
|
||||
|
||||
void set(Range<Long> lifespan, Address address, T value);
|
||||
public interface TracePropertyGetter<T> {
|
||||
/**
|
||||
* Get the class for values of the map
|
||||
*
|
||||
* @return the value class
|
||||
*/
|
||||
Class<? extends T> getValueClass();
|
||||
|
||||
/**
|
||||
* Get the value at the given address-snap pair
|
||||
*
|
||||
* @param snap the snap
|
||||
* @param address the address
|
||||
* @return the value
|
||||
*/
|
||||
T get(long snap, Address address);
|
||||
|
||||
/**
|
||||
* Get the union of address ranges for entries which intersect the given span
|
||||
*
|
||||
* @param span the range of snaps
|
||||
* @return the address set
|
||||
*/
|
||||
AddressSetView getAddressSetView(Range<Long> span);
|
||||
|
||||
void clear(Range<Long> span, AddressRange range);
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* 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.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.trace.model.property;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.TraceAddressSnapRange;
|
||||
|
||||
/**
|
||||
* A map from address-snap pairs to user-defined values in a {@link Trace}
|
||||
*/
|
||||
public interface TracePropertyMap<T> extends TracePropertySetter<T>, TracePropertyGetter<T> {
|
||||
/**
|
||||
* Get the class for values of the map
|
||||
*
|
||||
* @return the value class
|
||||
*/
|
||||
@Override
|
||||
Class<T> getValueClass();
|
||||
|
||||
/**
|
||||
* Get the entry at the given address-snap pair
|
||||
*
|
||||
* <p>
|
||||
* Because there exists {@link Map.Entry#setValue(Object)}, this method cannot be in
|
||||
* {@link TracePropertyGetter}.
|
||||
*
|
||||
* @param snap the snap
|
||||
* @param address the address
|
||||
* @return the entry, which includes the ranges and the value
|
||||
*/
|
||||
Map.Entry<TraceAddressSnapRange, T> getEntry(long snap, Address address);
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* 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.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.trace.model.property;
|
||||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
|
||||
public interface TracePropertySetter<T> {
|
||||
/**
|
||||
* Get the class for values of the map
|
||||
*
|
||||
* @return the value class
|
||||
*/
|
||||
Class<? super T> getValueClass();
|
||||
|
||||
/**
|
||||
* Set a value at the given address over the given lifespan
|
||||
*
|
||||
* @see #set(Range, AddressRange, Object)
|
||||
* @param lifespan the lifespan
|
||||
* @param address the address
|
||||
* @param value the value
|
||||
*/
|
||||
void set(Range<Long> lifespan, Address address, T value);
|
||||
|
||||
/**
|
||||
* Set a value over the given ranges
|
||||
*
|
||||
* <p>
|
||||
* Setting a value of null still creates an entry, so that Void-typed maps function.
|
||||
*
|
||||
* <p>
|
||||
* When setting an overlapping value, existing entries are deleted or truncated to make space
|
||||
* for the new entry. If an existing entry overlaps and its starting snap is contained in the
|
||||
* new entry's span, the existing entry is deleted, regardless of whether or not its ending snap
|
||||
* is also contained in the new entry's span. If the starting snap of the existing entry
|
||||
* precedes the span of the new entry, the existing entry is truncated -- its ending snap is set
|
||||
* to one less than the new entry's starting snap. Address ranges are never truncated.
|
||||
*
|
||||
* @param lifespan the lifespan
|
||||
* @param range the address range
|
||||
* @param value the value
|
||||
*/
|
||||
void set(Range<Long> lifespan, AddressRange range, T value);
|
||||
|
||||
/**
|
||||
* Remove or truncate entries so that the given span and range has no values
|
||||
*
|
||||
* <p>
|
||||
* This applies the same truncation rule as in {@link #set(Range, AddressRange, Object)}, except
|
||||
* that no replacement entry is created.
|
||||
*
|
||||
* @param span the range of snaps
|
||||
* @param range the address range
|
||||
*/
|
||||
void clear(Range<Long> span, AddressRange range);
|
||||
}
|
|
@ -30,7 +30,6 @@ import org.junit.*;
|
|||
|
||||
import db.DBHandle;
|
||||
import db.DBRecord;
|
||||
import ghidra.lifecycle.Unfinished;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.model.lang.LanguageID;
|
||||
|
@ -55,7 +54,7 @@ import ghidra.util.task.ConsoleTaskMonitor;
|
|||
*
|
||||
*/
|
||||
public class DBTraceAddressSnapRangePropertyMapSpaceTest
|
||||
extends AbstractGhidraHeadlessIntegrationTest implements Unfinished {
|
||||
extends AbstractGhidraHeadlessIntegrationTest {
|
||||
protected static class MyObject extends DBCachedDomainObjectAdapter implements AutoCloseable {
|
||||
private final DBCachedObjectStoreFactory factory;
|
||||
private final Language toy;
|
||||
|
|
|
@ -0,0 +1,378 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* 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.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.trace.database.property;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.program.model.util.TypeMismatchException;
|
||||
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
|
||||
import ghidra.trace.database.ToyDBTraceBuilder;
|
||||
import ghidra.trace.model.TraceAddressSnapRange;
|
||||
import ghidra.trace.model.property.*;
|
||||
import ghidra.util.ObjectStorage;
|
||||
import ghidra.util.Saveable;
|
||||
import ghidra.util.database.UndoableTransaction;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public class DBTraceAddressPropertyManagerTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||
protected static class MySaveable implements Saveable {
|
||||
protected int i;
|
||||
protected String str;
|
||||
|
||||
public MySaveable() {
|
||||
}
|
||||
|
||||
public MySaveable(int i, String str) {
|
||||
this.i = i;
|
||||
this.str = str;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof MySaveable)) {
|
||||
return false;
|
||||
}
|
||||
MySaveable that = (MySaveable) obj;
|
||||
return this.i == that.i && Objects.equals(this.str, that.str);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(i, str);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?>[] getObjectStorageFields() {
|
||||
return new Class[] { Integer.class, String.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(ObjectStorage objStorage) {
|
||||
objStorage.putInt(i);
|
||||
objStorage.putString(str);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restore(ObjectStorage objStorage) {
|
||||
i = objStorage.getInt();
|
||||
str = objStorage.getString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSchemaVersion() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUpgradeable(int oldSchemaVersion) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean upgrade(ObjectStorage oldObjStorage, int oldSchemaVersion,
|
||||
ObjectStorage currentObjStorage) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrivate() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class ExtMySaveable extends MySaveable {
|
||||
private float f;
|
||||
|
||||
public ExtMySaveable() {
|
||||
}
|
||||
|
||||
public ExtMySaveable(int i, String str, float f) {
|
||||
super(i, str);
|
||||
this.f = f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof ExtMySaveable)) {
|
||||
return false;
|
||||
}
|
||||
ExtMySaveable that = (ExtMySaveable) obj;
|
||||
return super.equals(that) && this.f == that.f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.i, this.str, this.f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?>[] getObjectStorageFields() {
|
||||
return new Class[] { Integer.class, String.class, Float.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(ObjectStorage objStorage) {
|
||||
super.save(objStorage);
|
||||
objStorage.putFloat(f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restore(ObjectStorage objStorage) {
|
||||
super.restore(objStorage);
|
||||
f = objStorage.getFloat();
|
||||
}
|
||||
}
|
||||
|
||||
protected static class Unsupported {
|
||||
}
|
||||
|
||||
ToyDBTraceBuilder tb;
|
||||
TraceAddressPropertyManager propertyManager;
|
||||
|
||||
@Before
|
||||
public void setUpPropertyManagerTest() throws Exception {
|
||||
tb = new ToyDBTraceBuilder("Testing", "Toy:BE:64:default");
|
||||
propertyManager = tb.trace.getAddressPropertyManager();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDownPropertyManagerTest() throws Exception {
|
||||
tb.close();
|
||||
}
|
||||
|
||||
protected void doTestCreatePropertyMap(Class<?> valueClass) throws Exception {
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
propertyManager.createPropertyMap("MyProp", valueClass);
|
||||
}
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
propertyManager.createPropertyMap("MyProp", valueClass);
|
||||
fail();
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateIntegerPropertyMap() throws Exception {
|
||||
doTestCreatePropertyMap(Integer.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateLongPropertyMap() throws Exception {
|
||||
doTestCreatePropertyMap(Long.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateStringPropertyMap() throws Exception {
|
||||
doTestCreatePropertyMap(String.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateVoidPropertyMap() throws Exception {
|
||||
doTestCreatePropertyMap(Void.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateSaveablePropertyMap() throws Exception {
|
||||
doTestCreatePropertyMap(MySaveable.class);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testCreateUnsupportedPropertyMap() throws Exception {
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
propertyManager.createPropertyMap("MyProp", Unsupported.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPropertyMap() throws Exception {
|
||||
assertNull(propertyManager.getPropertyMap("MyProp"));
|
||||
TracePropertyMap<String> map;
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
map = propertyManager.createPropertyMap("MyProp", String.class);
|
||||
}
|
||||
assertNotNull(map);
|
||||
assertSame(map, propertyManager.getPropertyMap("MyProp"));
|
||||
assertSame(map, propertyManager.getPropertyMap("MyProp", String.class));
|
||||
|
||||
try {
|
||||
propertyManager.getPropertyMap("MyProp", Integer.class);
|
||||
fail();
|
||||
}
|
||||
catch (TypeMismatchException e) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetOrCreatePropertyMap() throws Exception {
|
||||
assertNull(propertyManager.getPropertyMap("MyProp"));
|
||||
TracePropertyMap<String> map;
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
map = propertyManager.getOrCreatePropertyMap("MyProp", String.class);
|
||||
}
|
||||
assertNotNull(map);
|
||||
assertSame(map, propertyManager.getOrCreatePropertyMap("MyProp", String.class));
|
||||
|
||||
try {
|
||||
propertyManager.getOrCreatePropertyMap("MyProp", Integer.class);
|
||||
fail();
|
||||
}
|
||||
catch (TypeMismatchException e) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPropertyGetter() throws Exception {
|
||||
assertNull(propertyManager.getPropertyGetter("MyProp", String.class));
|
||||
TracePropertyMap<String> map;
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
map = propertyManager.createPropertyMap("MyProp", String.class);
|
||||
}
|
||||
assertNotNull(map);
|
||||
TracePropertyGetter<String> getter =
|
||||
propertyManager.getPropertyGetter("MyProp", String.class);
|
||||
assertSame(map, getter);
|
||||
assertSame(map, propertyManager.getPropertyGetter("MyProp", Object.class));
|
||||
|
||||
try {
|
||||
propertyManager.getPropertyGetter("MyProp", Integer.class);
|
||||
fail();
|
||||
}
|
||||
catch (TypeMismatchException e) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetOrCreatePropertySetter() throws Exception {
|
||||
TracePropertyMap<MySaveable> map;
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
map = propertyManager.createPropertyMap("MyProp", MySaveable.class);
|
||||
}
|
||||
assertNotNull(map);
|
||||
TracePropertySetter<ExtMySaveable> setter =
|
||||
propertyManager.getOrCreatePropertySetter("MyProp", ExtMySaveable.class);
|
||||
assertSame(map, setter);
|
||||
assertSame(map, propertyManager.getOrCreatePropertySetter("MyProp", MySaveable.class));
|
||||
|
||||
try {
|
||||
propertyManager.getOrCreatePropertySetter("MyProp", Saveable.class);
|
||||
fail();
|
||||
}
|
||||
catch (TypeMismatchException e) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllProperties() throws Exception {
|
||||
assertEquals(0, propertyManager.getAllProperties().size());
|
||||
TracePropertyMap<String> map;
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
map = propertyManager.createPropertyMap("MyProp", String.class);
|
||||
}
|
||||
assertNotNull(map);
|
||||
assertEquals(1, propertyManager.getAllProperties().size());
|
||||
assertSame(map, propertyManager.getAllProperties().get("MyProp"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapGetValueClass() throws Exception {
|
||||
TracePropertyMap<String> map;
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
map = propertyManager.createPropertyMap("MyProp", String.class);
|
||||
}
|
||||
assertSame(String.class, map.getValueClass());
|
||||
}
|
||||
|
||||
protected <T> void doTestMap(Class<T> valueClass, T value) throws Exception {
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
TracePropertyMap<T> map =
|
||||
propertyManager.createPropertyMap("MyProp", valueClass);
|
||||
assertSame(valueClass, map.getValueClass());
|
||||
|
||||
map.set(Range.atLeast(0L), tb.range(0x00400000, 0x00400003), value);
|
||||
assertEquals(value, map.get(4, tb.addr(0x00400001)));
|
||||
|
||||
assertEquals(tb.set(tb.range(0x00400000, 0x00400003)),
|
||||
map.getAddressSetView(Range.singleton(0L)));
|
||||
|
||||
Entry<TraceAddressSnapRange, T> entry = map.getEntry(4, tb.addr(0x00400001));
|
||||
assertEquals(value, entry.getValue());
|
||||
assertEquals(Range.atLeast(0L), entry.getKey().getLifespan());
|
||||
assertEquals(tb.range(0x00400000, 0x00400003), entry.getKey().getRange());
|
||||
|
||||
map.clear(Range.atLeast(11L), tb.range(0x00400000));
|
||||
|
||||
assertEquals(value, map.get(4, tb.addr(0x00400001)));
|
||||
assertNull(map.get(11, tb.addr(0x00400001)));
|
||||
}
|
||||
File file = tb.save();
|
||||
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder(file)) {
|
||||
TraceAddressPropertyManager propertyManager = tb.trace.getAddressPropertyManager();
|
||||
TracePropertyMap<T> map = propertyManager.getPropertyMap("MyProp", valueClass);
|
||||
assertNotNull(map);
|
||||
|
||||
Entry<TraceAddressSnapRange, T> entry = map.getEntry(4, tb.addr(0x00400001));
|
||||
assertEquals(value, entry.getValue());
|
||||
assertEquals(Range.closed(0L, 10L), entry.getKey().getLifespan());
|
||||
assertEquals(tb.range(0x00400000, 0x00400003), entry.getKey().getRange());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntegerMap() throws Exception {
|
||||
doTestMap(Integer.class, 6);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongMap() throws Exception {
|
||||
doTestMap(Long.class, 6L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringMap() throws Exception {
|
||||
doTestMap(String.class, "MyString");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVoidMap() throws Exception {
|
||||
doTestMap(Void.class, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveableMap() throws Exception {
|
||||
doTestMap(MySaveable.class, new MySaveable(6, "MyString"));
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue