mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
Merge branch 'GP-5619_emteere_VariousSpeedImprovements_VERSION2'
This commit is contained in:
commit
df505c40a3
25 changed files with 691 additions and 763 deletions
|
@ -18,6 +18,7 @@ package ghidra.util.datastruct;
|
||||||
import java.lang.ref.ReferenceQueue;
|
import java.lang.ref.ReferenceQueue;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>ObjectClass</code> provides a fixed-size long-key-based object cache.
|
* <code>ObjectClass</code> provides a fixed-size long-key-based object cache.
|
||||||
|
@ -27,12 +28,14 @@ import java.util.*;
|
||||||
* <p>
|
* <p>
|
||||||
* The weak cache is keyed, while the hard cache simply maintains the presence of
|
* The weak cache is keyed, while the hard cache simply maintains the presence of
|
||||||
* an object in the weak cache.
|
* an object in the weak cache.
|
||||||
|
*
|
||||||
|
* @param <T> Object type held by cache
|
||||||
*/
|
*/
|
||||||
public class ObjectCache {
|
public class ObjectCache<T> {
|
||||||
|
|
||||||
private Map<Long, KeyedSoftReference<?>> hashTable;
|
private Map<Long, KeyedSoftReference<T>> hashTable;
|
||||||
private ReferenceQueue<Object> refQueue;
|
private ReferenceQueue<T> refQueue;
|
||||||
private LinkedList<Object> hardCache;
|
private LinkedList<T> hardCache;
|
||||||
private int hardCacheSize;
|
private int hardCacheSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -61,10 +64,10 @@ public class ObjectCache {
|
||||||
* @param key object key
|
* @param key object key
|
||||||
* @return cached object
|
* @return cached object
|
||||||
*/
|
*/
|
||||||
public synchronized Object get(long key) {
|
public synchronized T get(long key) {
|
||||||
WeakReference<?> ref = hashTable.get(key);
|
WeakReference<T> ref = hashTable.get(key);
|
||||||
if (ref != null) {
|
if (ref != null) {
|
||||||
Object obj = ref.get();
|
T obj = ref.get();
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
hashTable.remove(key);
|
hashTable.remove(key);
|
||||||
}
|
}
|
||||||
|
@ -74,6 +77,30 @@ public class ObjectCache {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current cached object which corresponds to specified {@code key} if contained in
|
||||||
|
* cache, otherwise the {@code mappingFunction} will be invoked to instantiate a new object
|
||||||
|
* where that object will be added to the cache and returned. If the {@code mappingFunction}
|
||||||
|
* returns null nothing will be added to the cache and null will be returned by this method.
|
||||||
|
*
|
||||||
|
* @param key object key
|
||||||
|
* @param mappingFunction function used to obtain a new object if not currently present
|
||||||
|
* in cache.
|
||||||
|
* @return cached object
|
||||||
|
*/
|
||||||
|
public synchronized T computeIfAbsent(long key, Function<Long, T> mappingFunction) {
|
||||||
|
Objects.requireNonNull(mappingFunction);
|
||||||
|
T oldValue = get(key);
|
||||||
|
if (oldValue != null) {
|
||||||
|
return oldValue;
|
||||||
|
}
|
||||||
|
T newValue = mappingFunction.apply(key);
|
||||||
|
if (newValue != null) {
|
||||||
|
put(key, newValue);
|
||||||
|
}
|
||||||
|
return newValue;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the hard cache size
|
* Return the hard cache size
|
||||||
* @return the hard cache size
|
* @return the hard cache size
|
||||||
|
@ -98,9 +125,9 @@ public class ObjectCache {
|
||||||
* @param key object key
|
* @param key object key
|
||||||
* @param obj the object
|
* @param obj the object
|
||||||
*/
|
*/
|
||||||
public synchronized void put(long key, Object obj) {
|
public synchronized void put(long key, T obj) {
|
||||||
processQueue();
|
processQueue();
|
||||||
KeyedSoftReference<?> ref = new KeyedSoftReference<>(key, obj, refQueue);
|
KeyedSoftReference<T> ref = new KeyedSoftReference<>(key, obj, refQueue);
|
||||||
hashTable.put(key, ref);
|
hashTable.put(key, ref);
|
||||||
addToHardCache(obj);
|
addToHardCache(obj);
|
||||||
}
|
}
|
||||||
|
@ -112,7 +139,7 @@ public class ObjectCache {
|
||||||
*/
|
*/
|
||||||
public synchronized void remove(long key) {
|
public synchronized void remove(long key) {
|
||||||
processQueue();
|
processQueue();
|
||||||
KeyedSoftReference<?> ref = hashTable.get(key);
|
KeyedSoftReference<T> ref = hashTable.get(key);
|
||||||
if (ref != null) {
|
if (ref != null) {
|
||||||
ref.clear();
|
ref.clear();
|
||||||
hashTable.remove(key);
|
hashTable.remove(key);
|
||||||
|
@ -123,7 +150,7 @@ public class ObjectCache {
|
||||||
* Add the specified object to the hard cache.
|
* Add the specified object to the hard cache.
|
||||||
* @param obj object
|
* @param obj object
|
||||||
*/
|
*/
|
||||||
private void addToHardCache(Object obj) {
|
private void addToHardCache(T obj) {
|
||||||
hardCache.addLast(obj);
|
hardCache.addLast(obj);
|
||||||
if (hardCache.size() > hardCacheSize) {
|
if (hardCache.size() > hardCacheSize) {
|
||||||
hardCache.removeFirst();
|
hardCache.removeFirst();
|
||||||
|
@ -134,8 +161,8 @@ public class ObjectCache {
|
||||||
* Cleanup weak cache
|
* Cleanup weak cache
|
||||||
*/
|
*/
|
||||||
private void processQueue() {
|
private void processQueue() {
|
||||||
KeyedSoftReference<?> ref;
|
KeyedSoftReference<? extends T> ref;
|
||||||
while ((ref = (KeyedSoftReference<?>) refQueue.poll()) != null) {
|
while ((ref = (KeyedSoftReference<? extends T>) refQueue.poll()) != null) {
|
||||||
hashTable.remove(ref.getKey());
|
hashTable.remove(ref.getKey());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ public abstract class DatabaseObject {
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
private final DBObjectCache cache;
|
private final DBObjectCache cache;
|
||||||
private volatile int invalidateCount;
|
private volatile int invalidateCount;
|
||||||
|
private boolean refreshing = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new DatabaseObject and adds it to the specified cache.
|
* Constructs a new DatabaseObject and adds it to the specified cache.
|
||||||
|
@ -91,6 +92,7 @@ public abstract class DatabaseObject {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if object is currently invalid and must be validated prior to further use.
|
* Returns true if object is currently invalid and must be validated prior to further use.
|
||||||
|
* A deleted object will be considered valid since it cannot be refreshed.
|
||||||
* An invalid object may result from a cache invalidation which corresponds to wide-spread
|
* An invalid object may result from a cache invalidation which corresponds to wide-spread
|
||||||
* record changes. A common situation where this can occur is an undo/redo operation
|
* record changes. A common situation where this can occur is an undo/redo operation
|
||||||
* against the underlying database. The methods {@link #checkIsValid()}, {@link #checkDeleted()},
|
* against the underlying database. The methods {@link #checkIsValid()}, {@link #checkDeleted()},
|
||||||
|
@ -128,23 +130,41 @@ public abstract class DatabaseObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether this object is still valid. If the object is invalid, the object will attempt
|
* Check whether this object is still valid. If the object is invalid and not deleted, the
|
||||||
* to refresh itself using the specified record. If the refresh fails, the object will be marked
|
* object will attempt to refresh itself using the specified record. If the refresh fails,
|
||||||
* as deleted and removed from cache. If this object is already marked as deleted, the record
|
* the object will be marked as deleted and removed from cache. If this object is already
|
||||||
* can not be used to refresh the object.
|
* marked as deleted a refresh will not be perormed.
|
||||||
|
* <P>
|
||||||
|
* This method may invoke {@link #refresh(DBRecord)} to perform a refresh. It is important
|
||||||
|
* that such a refresh avoid recursing back into this method.
|
||||||
*
|
*
|
||||||
* @param record optional record which may be used to refresh invalid object
|
* @param record optional record which may be used to refresh invalid object
|
||||||
* @return true if the object is valid.
|
* @return true if the object is valid or false if it has been deleted.
|
||||||
*/
|
*/
|
||||||
protected boolean checkIsValid(DBRecord record) {
|
protected boolean checkIsValid(DBRecord record) {
|
||||||
if (isInvalid()) {
|
if (isInvalid()) {
|
||||||
setValid();// prevent checkIsValid recursion during refresh
|
if (refreshing) {
|
||||||
if (!refresh(record)) {
|
// NOTE: We need to correct such recursion cases which should be
|
||||||
|
// avoided since object is not in a valid state until refresh completed.
|
||||||
|
return !deleted;
|
||||||
|
}
|
||||||
|
refreshing = true;
|
||||||
|
try {
|
||||||
|
if (refresh(record)) {
|
||||||
|
// Object is valid
|
||||||
|
setValid();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Object has been deleted
|
||||||
if (cache != null) {
|
if (cache != null) {
|
||||||
cache.delete(key);
|
cache.delete(key);
|
||||||
}
|
}
|
||||||
setDeleted();
|
setDeleted();
|
||||||
setInvalid();
|
return false;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
refreshing = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return !deleted;
|
return !deleted;
|
||||||
|
@ -152,14 +172,15 @@ public abstract class DatabaseObject {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method provides a cheap (lock free) way to test if an object is valid. If this object is
|
* This method provides a cheap (lock free) way to test if an object is valid. If this object is
|
||||||
* invalid, then the lock will be used to refresh as needed.
|
* invalid and not deleted, then the lock will be used to refresh as needed. A deleted object
|
||||||
|
* will not be refreshed.
|
||||||
*
|
*
|
||||||
* @param lock the lock that will be used if the object needs to be refreshed.
|
* @param lock the lock that will be used if the object needs to be refreshed.
|
||||||
* @return true if object is valid, else false if deleted
|
* @return true if object is valid or false if deleted
|
||||||
*/
|
*/
|
||||||
protected boolean validate(Lock lock) {
|
protected boolean validate(Lock lock) {
|
||||||
if (!isInvalid()) {
|
if (!isInvalid()) {
|
||||||
return true;
|
return !deleted;
|
||||||
}
|
}
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -3207,8 +3207,8 @@ public class CodeManager implements ErrorHandler, ManagerDB {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
cache.invalidate();
|
cache.invalidate();
|
||||||
lengthMgr.invalidateCache();
|
lengthMgr.invalidate();
|
||||||
compositeMgr.invalidateCache();
|
compositeMgr.invalidate();
|
||||||
protoMgr.clearCache();
|
protoMgr.clearCache();
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
|
|
@ -65,7 +65,7 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
* @param cacheKey the cache key (dataComponent does not use the address)
|
* @param cacheKey the cache key (dataComponent does not use the address)
|
||||||
* @param address min address of this code unit
|
* @param address min address of this code unit
|
||||||
* @param addr index for min address
|
* @param addr index for min address
|
||||||
* @param the length of the codeunit.
|
* @param length the length of the codeunit.
|
||||||
*/
|
*/
|
||||||
public CodeUnitDB(CodeManager codeMgr, DBObjectCache<? extends CodeUnitDB> cache, long cacheKey,
|
public CodeUnitDB(CodeManager codeMgr, DBObjectCache<? extends CodeUnitDB> cache, long cacheKey,
|
||||||
Address address, long addr, int length) {
|
Address address, long addr, int length) {
|
||||||
|
@ -95,21 +95,6 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
return !hasBeenDeleted(record);
|
return !hasBeenDeleted(record);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check this code units validity when the lock/checkIsValid is not used and refresh if necessary.
|
|
||||||
*/
|
|
||||||
protected void refreshIfNeeded() {
|
|
||||||
if (isInvalid()) {
|
|
||||||
lock.acquire();
|
|
||||||
try {
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform any refresh necessary and determine if this code unit has been deleted.
|
* Perform any refresh necessary and determine if this code unit has been deleted.
|
||||||
* If a record has been provided, it may be used to facilitate a refresh without
|
* If a record has been provided, it may be used to facilitate a refresh without
|
||||||
|
@ -122,7 +107,7 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addMnemonicReference(Address refAddr, RefType refType, SourceType sourceType) {
|
public void addMnemonicReference(Address refAddr, RefType refType, SourceType sourceType) {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
refMgr.addMemoryReference(address, refAddr, refType, sourceType, MNEMONIC);
|
refMgr.addMemoryReference(address, refAddr, refType, sourceType, MNEMONIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,13 +119,12 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
@Override
|
@Override
|
||||||
public void addOperandReference(int opIndex, Address refAddr, RefType type,
|
public void addOperandReference(int opIndex, Address refAddr, RefType type,
|
||||||
SourceType sourceType) {
|
SourceType sourceType) {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
refMgr.addMemoryReference(address, refAddr, type, sourceType, opIndex);
|
refMgr.addMemoryReference(address, refAddr, type, sourceType, opIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(Address a) {
|
public int compareTo(Address a) {
|
||||||
refreshIfNeeded();
|
|
||||||
if (contains(a)) {
|
if (contains(a)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -149,13 +133,13 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean contains(Address testAddr) {
|
public boolean contains(Address testAddr) {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
return address.compareTo(testAddr) <= 0 && testAddr.compareTo(getMaxAddress()) <= 0;
|
return address.compareTo(testAddr) <= 0 && testAddr.compareTo(getMaxAddress()) <= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getAddressString(boolean showBlockName, boolean pad) {
|
public String getAddressString(boolean showBlockName, boolean pad) {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
Address cuAddress = address;
|
Address cuAddress = address;
|
||||||
String addressString = cuAddress.toString(false, pad);
|
String addressString = cuAddress.toString(false, pad);
|
||||||
if (showBlockName) {
|
if (showBlockName) {
|
||||||
|
@ -231,7 +215,7 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ExternalReference getExternalReference(int opIndex) {
|
public ExternalReference getExternalReference(int opIndex) {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
Reference[] refs = refMgr.getReferencesFrom(address, opIndex);
|
Reference[] refs = refMgr.getReferencesFrom(address, opIndex);
|
||||||
for (Reference element : refs) {
|
for (Reference element : refs) {
|
||||||
if (element.isExternalReference()) {
|
if (element.isExternalReference()) {
|
||||||
|
@ -249,7 +233,7 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
throw NoValueException.noValueException;
|
throw NoValueException.noValueException;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
return pm.getInt(address);
|
return pm.getInt(address);
|
||||||
}
|
}
|
||||||
catch (ConcurrentModificationException e) {
|
catch (ConcurrentModificationException e) {
|
||||||
|
@ -259,7 +243,7 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getLabel() {
|
public String getLabel() {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
SymbolTable st = codeMgr.getSymbolTable();
|
SymbolTable st = codeMgr.getSymbolTable();
|
||||||
Symbol symbol = st.getPrimarySymbol(address);
|
Symbol symbol = st.getPrimarySymbol(address);
|
||||||
if (symbol != null) {
|
if (symbol != null) {
|
||||||
|
@ -279,7 +263,7 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address getMaxAddress() {
|
public Address getMaxAddress() {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
if (endAddr == null) {
|
if (endAddr == null) {
|
||||||
endAddr = getLength() == 0 ? address : address.add(getLength() - 1);
|
endAddr = getLength() == 0 ? address : address.add(getLength() - 1);
|
||||||
}
|
}
|
||||||
|
@ -288,20 +272,19 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address getMinAddress() {
|
public Address getMinAddress() {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address getAddress() {
|
public Address getAddress() {
|
||||||
// TODO: Not sure why this method exists?
|
validate(lock);
|
||||||
refreshIfNeeded();
|
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Reference[] getMnemonicReferences() {
|
public Reference[] getMnemonicReferences() {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
return refMgr.getReferencesFrom(address, MNEMONIC);
|
return refMgr.getReferencesFrom(address, MNEMONIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,7 +294,7 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
ObjectPropertyMap<?> pm = upm.getObjectPropertyMap(name);
|
ObjectPropertyMap<?> pm = upm.getObjectPropertyMap(name);
|
||||||
if (pm != null) {
|
if (pm != null) {
|
||||||
try {
|
try {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
return pm.get(address);
|
return pm.get(address);
|
||||||
}
|
}
|
||||||
catch (ConcurrentModificationException e) {
|
catch (ConcurrentModificationException e) {
|
||||||
|
@ -322,19 +305,19 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Reference[] getOperandReferences(int opIndex) {
|
public Reference[] getOperandReferences(int opIndex) {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
return refMgr.getReferencesFrom(address, opIndex);
|
return refMgr.getReferencesFrom(address, opIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Reference getPrimaryReference(int index) {
|
public Reference getPrimaryReference(int index) {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
return refMgr.getPrimaryReferenceFrom(address, index);
|
return refMgr.getPrimaryReferenceFrom(address, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Symbol getPrimarySymbol() {
|
public Symbol getPrimarySymbol() {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
SymbolTable st = codeMgr.getSymbolTable();
|
SymbolTable st = codeMgr.getSymbolTable();
|
||||||
return st.getPrimarySymbol(address);
|
return st.getPrimarySymbol(address);
|
||||||
}
|
}
|
||||||
|
@ -346,13 +329,13 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Reference[] getReferencesFrom() {
|
public Reference[] getReferencesFrom() {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
return refMgr.getReferencesFrom(address);
|
return refMgr.getReferencesFrom(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ReferenceIterator getReferenceIteratorTo() {
|
public ReferenceIterator getReferenceIteratorTo() {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
return program.getReferenceManager().getReferencesTo(address);
|
return program.getReferenceManager().getReferencesTo(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,7 +345,7 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
StringPropertyMap pm = upm.getStringPropertyMap(name);
|
StringPropertyMap pm = upm.getStringPropertyMap(name);
|
||||||
if (pm != null) {
|
if (pm != null) {
|
||||||
try {
|
try {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
return pm.getString(address);
|
return pm.getString(address);
|
||||||
}
|
}
|
||||||
catch (ConcurrentModificationException e) {
|
catch (ConcurrentModificationException e) {
|
||||||
|
@ -373,7 +356,7 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Symbol[] getSymbols() {
|
public Symbol[] getSymbols() {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
SymbolTable st = codeMgr.getSymbolTable();
|
SymbolTable st = codeMgr.getSymbolTable();
|
||||||
return st.getSymbols(address);
|
return st.getSymbols(address);
|
||||||
}
|
}
|
||||||
|
@ -384,7 +367,7 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
VoidPropertyMap pm = upm.getVoidPropertyMap(name);
|
VoidPropertyMap pm = upm.getVoidPropertyMap(name);
|
||||||
if (pm != null) {
|
if (pm != null) {
|
||||||
try {
|
try {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
return pm.hasProperty(address);
|
return pm.hasProperty(address);
|
||||||
}
|
}
|
||||||
catch (ConcurrentModificationException e) {
|
catch (ConcurrentModificationException e) {
|
||||||
|
@ -399,7 +382,7 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
PropertyMap<?> pm = upm.getPropertyMap(name);
|
PropertyMap<?> pm = upm.getPropertyMap(name);
|
||||||
if (pm != null) {
|
if (pm != null) {
|
||||||
try {
|
try {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
return pm.hasProperty(address);
|
return pm.hasProperty(address);
|
||||||
}
|
}
|
||||||
catch (ConcurrentModificationException e) {
|
catch (ConcurrentModificationException e) {
|
||||||
|
@ -424,7 +407,7 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeMnemonicReference(Address refAddr) {
|
public void removeMnemonicReference(Address refAddr) {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
Reference ref = refMgr.getReference(address, refAddr, MNEMONIC);
|
Reference ref = refMgr.getReference(address, refAddr, MNEMONIC);
|
||||||
if (ref != null) {
|
if (ref != null) {
|
||||||
program.getReferenceManager().delete(ref);
|
program.getReferenceManager().delete(ref);
|
||||||
|
@ -433,7 +416,7 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeOperandReference(int opIndex, Address refAddr) {
|
public void removeOperandReference(int opIndex, Address refAddr) {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
Reference ref = refMgr.getReference(address, refAddr, opIndex);
|
Reference ref = refMgr.getReference(address, refAddr, opIndex);
|
||||||
if (ref != null) {
|
if (ref != null) {
|
||||||
program.getReferenceManager().delete(ref);
|
program.getReferenceManager().delete(ref);
|
||||||
|
@ -446,7 +429,7 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
PropertyMap<?> pm = upm.getPropertyMap(name);
|
PropertyMap<?> pm = upm.getPropertyMap(name);
|
||||||
if (pm != null) {
|
if (pm != null) {
|
||||||
try {
|
try {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
pm.remove(address);
|
pm.remove(address);
|
||||||
}
|
}
|
||||||
catch (ConcurrentModificationException e) {
|
catch (ConcurrentModificationException e) {
|
||||||
|
@ -607,7 +590,7 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setStackReference(int opIndex, int offset, SourceType sourceType, RefType refType) {
|
public void setStackReference(int opIndex, int offset, SourceType sourceType, RefType refType) {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
validateOpIndex(opIndex);
|
validateOpIndex(opIndex);
|
||||||
refMgr.addStackReference(address, opIndex, offset, refType, sourceType);
|
refMgr.addStackReference(address, opIndex, offset, refType, sourceType);
|
||||||
}
|
}
|
||||||
|
@ -615,14 +598,14 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
@Override
|
@Override
|
||||||
public void setRegisterReference(int opIndex, Register reg, SourceType sourceType,
|
public void setRegisterReference(int opIndex, Register reg, SourceType sourceType,
|
||||||
RefType refType) {
|
RefType refType) {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
validateOpIndex(opIndex);
|
validateOpIndex(opIndex);
|
||||||
refMgr.addRegisterReference(address, opIndex, reg, refType, sourceType);
|
refMgr.addRegisterReference(address, opIndex, reg, refType, sourceType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getBytes(byte[] b, int offset) {
|
public int getBytes(byte[] b, int offset) {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
byte localBytes[] = populateByteArray();
|
byte localBytes[] = populateByteArray();
|
||||||
if (offset >= 0 && (offset + b.length) <= localBytes.length) {
|
if (offset >= 0 && (offset + b.length) <= localBytes.length) {
|
||||||
System.arraycopy(localBytes, offset, b, 0, b.length);
|
System.arraycopy(localBytes, offset, b, 0, b.length);
|
||||||
|
@ -639,10 +622,10 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] getBytes() throws MemoryAccessException {
|
public byte[] getBytes() throws MemoryAccessException {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
byte localBytes[] = populateByteArray();
|
byte localBytes[] = populateByteArray();
|
||||||
int locallen = getLength();
|
int locallen = getLength();
|
||||||
if (localBytes.length >= locallen ) {
|
if (localBytes.length >= locallen) {
|
||||||
byte[] b = new byte[locallen];
|
byte[] b = new byte[locallen];
|
||||||
System.arraycopy(localBytes, 0, b, 0, b.length);
|
System.arraycopy(localBytes, 0, b, 0, b.length);
|
||||||
return b;
|
return b;
|
||||||
|
@ -659,7 +642,7 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte getByte(int offset) throws MemoryAccessException {
|
public byte getByte(int offset) throws MemoryAccessException {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
byte localBytes[] = populateByteArray();
|
byte localBytes[] = populateByteArray();
|
||||||
if (offset >= 0 && offset < localBytes.length) {
|
if (offset >= 0 && offset < localBytes.length) {
|
||||||
return localBytes[offset];
|
return localBytes[offset];
|
||||||
|
@ -680,31 +663,31 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BigInteger getValue(Register register, boolean signed) {
|
public BigInteger getValue(Register register, boolean signed) {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
return programContext.getValue(register, address, signed);
|
return programContext.getValue(register, address, signed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RegisterValue getRegisterValue(Register register) {
|
public RegisterValue getRegisterValue(Register register) {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
return programContext.getRegisterValue(register, address);
|
return programContext.getRegisterValue(register, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setValue(Register register, BigInteger value) throws ContextChangeException {
|
public void setValue(Register register, BigInteger value) throws ContextChangeException {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
programContext.setValue(register, address, address, value);
|
programContext.setValue(register, address, address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearRegister(Register register) throws ContextChangeException {
|
public void clearRegister(Register register) throws ContextChangeException {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
programContext.setValue(register, address, address, null);
|
programContext.setValue(register, address, address, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setRegisterValue(RegisterValue value) throws ContextChangeException {
|
public void setRegisterValue(RegisterValue value) throws ContextChangeException {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
programContext.setRegisterValue(address, address, value);
|
programContext.setRegisterValue(address, address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -725,7 +708,7 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasValue(Register register) {
|
public boolean hasValue(Register register) {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
return programContext.getValue(register, address, false) != null;
|
return programContext.getValue(register, address, false) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -818,7 +801,7 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void getBytesInCodeUnit(byte[] buffer, int bufferOffset) throws MemoryAccessException {
|
public void getBytesInCodeUnit(byte[] buffer, int bufferOffset) throws MemoryAccessException {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
byte[] codeUnitBytes = getBytes();
|
byte[] codeUnitBytes = getBytes();
|
||||||
System.arraycopy(codeUnitBytes, 0, buffer, bufferOffset,
|
System.arraycopy(codeUnitBytes, 0, buffer, bufferOffset,
|
||||||
Math.min(buffer.length, getLength()));
|
Math.min(buffer.length, getLength()));
|
||||||
|
|
|
@ -197,7 +197,7 @@ class DataDB extends CodeUnitDB implements Data {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addValueReference(Address refAddr, RefType type) {
|
public void addValueReference(Address refAddr, RefType type) {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
refMgr.addMemoryReference(address, refAddr, type, SourceType.USER_DEFINED,
|
refMgr.addMemoryReference(address, refAddr, type, SourceType.USER_DEFINED,
|
||||||
CodeManager.DATA_OP_INDEX);
|
CodeManager.DATA_OP_INDEX);
|
||||||
}
|
}
|
||||||
|
@ -379,19 +379,19 @@ class DataDB extends CodeUnitDB implements Data {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
|
public boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
return dataMgr.isChangeAllowed(this, settingsDefinition);
|
return dataMgr.isChangeAllowed(this, settingsDefinition);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearSetting(String name) {
|
public void clearSetting(String name) {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
dataMgr.clearSetting(this, name);
|
dataMgr.clearSetting(this, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long getLong(String name) {
|
public Long getLong(String name) {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
Long value = dataMgr.getLongSettingsValue(this, name);
|
Long value = dataMgr.getLongSettingsValue(this, name);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
value = getDefaultSettings().getLong(name);
|
value = getDefaultSettings().getLong(name);
|
||||||
|
@ -401,13 +401,13 @@ class DataDB extends CodeUnitDB implements Data {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] getNames() {
|
public String[] getNames() {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
return dataMgr.getInstanceSettingsNames(this);
|
return dataMgr.getInstanceSettingsNames(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getString(String name) {
|
public String getString(String name) {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
String value = dataMgr.getStringSettingsValue(this, name);
|
String value = dataMgr.getStringSettingsValue(this, name);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
value = getDefaultSettings().getString(name);
|
value = getDefaultSettings().getString(name);
|
||||||
|
@ -417,7 +417,7 @@ class DataDB extends CodeUnitDB implements Data {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getValue(String name) {
|
public Object getValue(String name) {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
Object value = dataMgr.getSettings(this, name);
|
Object value = dataMgr.getSettings(this, name);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
value = getDefaultSettings().getValue(name);
|
value = getDefaultSettings().getValue(name);
|
||||||
|
@ -427,19 +427,19 @@ class DataDB extends CodeUnitDB implements Data {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setLong(String name, long value) {
|
public void setLong(String name, long value) {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
dataMgr.setLongSettingsValue(this, name, value);
|
dataMgr.setLongSettingsValue(this, name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setString(String name, String value) {
|
public void setString(String name, String value) {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
dataMgr.setStringSettingsValue(this, name, value);
|
dataMgr.setStringSettingsValue(this, name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setValue(String name, Object value) {
|
public void setValue(String name, Object value) {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
dataMgr.setSettings(this, name, value);
|
dataMgr.setSettings(this, name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -650,7 +650,7 @@ class DataDB extends CodeUnitDB implements Data {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getPathName() {
|
public String getPathName() {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
Address cuAddress = address;
|
Address cuAddress = address;
|
||||||
SymbolTable st = program.getSymbolTable();
|
SymbolTable st = program.getSymbolTable();
|
||||||
Symbol symbol = st.getPrimarySymbol(cuAddress);
|
Symbol symbol = st.getPrimarySymbol(cuAddress);
|
||||||
|
@ -763,13 +763,13 @@ class DataDB extends CodeUnitDB implements Data {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearAllSettings() {
|
public void clearAllSettings() {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
dataMgr.clearAllSettings(this);
|
dataMgr.clearAllSettings(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
return dataMgr.isEmptySetting(this);
|
return dataMgr.isEmptySetting(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,9 +54,11 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
||||||
private FlowOverride flowOverride;
|
private FlowOverride flowOverride;
|
||||||
private int lengthOverride;
|
private int lengthOverride;
|
||||||
private final static Address[] EMPTY_ADDR_ARRAY = new Address[0];
|
private final static Address[] EMPTY_ADDR_ARRAY = new Address[0];
|
||||||
|
private final static Object[] EMPTY_OBJ_ARRAY = new Object[0];
|
||||||
private volatile boolean clearingFallThroughs = false;
|
private volatile boolean clearingFallThroughs = false;
|
||||||
|
|
||||||
private ParserContext parserContext;
|
private ParserContext parserContext; // uses lazy initialization
|
||||||
|
private String mnemonicString; // uses lazy initialization
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new InstructionDB.
|
* Construct a new InstructionDB.
|
||||||
|
@ -80,6 +82,7 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
||||||
@Override
|
@Override
|
||||||
protected boolean refresh(DBRecord record) {
|
protected boolean refresh(DBRecord record) {
|
||||||
parserContext = null;
|
parserContext = null;
|
||||||
|
mnemonicString = null;
|
||||||
return super.refresh(record);
|
return super.refresh(record);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,12 +243,12 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isInDelaySlot()) {
|
if (isInDelaySlot()) {
|
||||||
// If this instruction is within delay-slot, return a null fall-from address if
|
// If this instruction is within delay-slot, return a null fall-from address if
|
||||||
// previous instruction (i.e., instruction with delay slot, found above)
|
// previous instruction (i.e., instruction with delay slot, found above)
|
||||||
// does not have a fallthrough and this instruction has a ref or label on it.
|
// does not have a fallthrough and this instruction has a ref or label on it.
|
||||||
if (!instr.hasFallthrough() &&
|
if (!instr.hasFallthrough() &&
|
||||||
program.getSymbolTable().hasSymbol(this.getMinAddress())) {
|
program.getSymbolTable().hasSymbol(getMinAddress())) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// Return previous instruction's address (i.e., instruction with delay slot, found above)
|
// Return previous instruction's address (i.e., instruction with delay slot, found above)
|
||||||
|
@ -276,22 +279,15 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address getFallThrough() {
|
public Address getFallThrough() {
|
||||||
lock.acquire();
|
|
||||||
try {
|
|
||||||
checkIsValid();
|
|
||||||
if (isFallThroughOverridden()) {
|
if (isFallThroughOverridden()) {
|
||||||
return getFallThroughReference();
|
return getFallThroughReference();
|
||||||
}
|
}
|
||||||
return getDefaultFallThrough();
|
return getDefaultFallThrough();
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address[] getFlows() {
|
public Address[] getFlows() {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
Reference[] refs = refMgr.getFlowReferencesFrom(address);
|
Reference[] refs = refMgr.getFlowReferencesFrom(address);
|
||||||
if (refs.length == 0) {
|
if (refs.length == 0) {
|
||||||
return EMPTY_ADDR_ARRAY;
|
return EMPTY_ADDR_ARRAY;
|
||||||
|
@ -313,6 +309,7 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address[] getDefaultFlows() {
|
public Address[] getDefaultFlows() {
|
||||||
|
validate(lock);
|
||||||
Address[] flows = proto.getFlows(this);
|
Address[] flows = proto.getFlows(this);
|
||||||
if (flowOverride == FlowOverride.RETURN && flows.length == 1) {
|
if (flowOverride == FlowOverride.RETURN && flows.length == 1) {
|
||||||
return EMPTY_ADDR_ARRAY;
|
return EMPTY_ADDR_ARRAY;
|
||||||
|
@ -322,17 +319,23 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FlowType getFlowType() {
|
public FlowType getFlowType() {
|
||||||
|
validate(lock);
|
||||||
return FlowOverride.getModifiedFlowType(proto.getFlowType(this), flowOverride);
|
return FlowOverride.getModifiedFlowType(proto.getFlowType(this), flowOverride);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Instruction getNext() {
|
public Instruction getNext() {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
return codeMgr.getInstructionAfter(address);
|
return codeMgr.getInstructionAfter(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RefType getOperandRefType(int opIndex) {
|
public RefType getOperandRefType(int opIndex) {
|
||||||
|
|
||||||
|
if (opIndex < 0 || opIndex >= getNumOperands()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// always reflects current flowOverride
|
// always reflects current flowOverride
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
|
@ -346,6 +349,11 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSeparator(int opIndex) {
|
public String getSeparator(int opIndex) {
|
||||||
|
|
||||||
|
if (opIndex < 0 || opIndex >= getNumOperands()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
return proto.getSeparator(opIndex, this);
|
return proto.getSeparator(opIndex, this);
|
||||||
|
@ -424,12 +432,14 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object[] getOpObjects(int opIndex) {
|
public Object[] getOpObjects(int opIndex) {
|
||||||
|
|
||||||
|
if (opIndex < 0 || opIndex >= getNumOperands()) {
|
||||||
|
return EMPTY_OBJ_ARRAY;
|
||||||
|
}
|
||||||
|
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
checkIsValid();
|
checkIsValid();
|
||||||
if (opIndex < 0 || opIndex >= getNumOperands()) {
|
|
||||||
return new Object[0];
|
|
||||||
}
|
|
||||||
return proto.getOpObjects(opIndex, this);
|
return proto.getOpObjects(opIndex, this);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -439,7 +449,7 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Instruction getPrevious() {
|
public Instruction getPrevious() {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
return codeMgr.getInstructionBefore(address);
|
return codeMgr.getInstructionBefore(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -450,12 +460,14 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Register getRegister(int opIndex) {
|
public Register getRegister(int opIndex) {
|
||||||
|
|
||||||
|
if (opIndex < 0 || opIndex >= getNumOperands()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
checkIsValid();
|
checkIsValid();
|
||||||
if (opIndex < 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return proto.getRegister(opIndex, this);
|
return proto.getRegister(opIndex, this);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -494,6 +506,11 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address getAddress(int opIndex) {
|
public Address getAddress(int opIndex) {
|
||||||
|
|
||||||
|
if (opIndex < 0 || opIndex >= getNumOperands()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
checkIsValid();
|
checkIsValid();
|
||||||
|
@ -501,9 +518,7 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
||||||
if (ref != null) {
|
if (ref != null) {
|
||||||
return ref.getToAddress();
|
return ref.getToAddress();
|
||||||
}
|
}
|
||||||
if (opIndex < 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
int opType = proto.getOpType(opIndex, this);
|
int opType = proto.getOpType(opIndex, this);
|
||||||
|
|
||||||
if (OperandType.isAddress(opType)) {
|
if (OperandType.isAddress(opType)) {
|
||||||
|
@ -550,10 +565,16 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMnemonicString() {
|
public String getMnemonicString() {
|
||||||
|
validate(lock);
|
||||||
|
String curMnemonic = mnemonicString;
|
||||||
|
if (curMnemonic != null) {
|
||||||
|
return curMnemonic;
|
||||||
|
}
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
checkIsValid();
|
checkIsValid();
|
||||||
return proto.getMnemonic(this);
|
mnemonicString = proto.getMnemonic(this);
|
||||||
|
return mnemonicString;
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
lock.release();
|
lock.release();
|
||||||
|
@ -567,12 +588,14 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Scalar getScalar(int opIndex) {
|
public Scalar getScalar(int opIndex) {
|
||||||
|
|
||||||
|
if (opIndex < 0 || opIndex >= getNumOperands()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
checkIsValid();
|
checkIsValid();
|
||||||
if (opIndex < 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return proto.getScalar(opIndex, this);
|
return proto.getScalar(opIndex, this);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -693,6 +716,7 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFallThroughOverridden() {
|
public boolean isFallThroughOverridden() {
|
||||||
|
validate(lock);
|
||||||
return (flags & FALLTHROUGH_SET_MASK) != 0;
|
return (flags & FALLTHROUGH_SET_MASK) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -705,7 +729,7 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
||||||
if (clearingFallThroughs) {
|
if (clearingFallThroughs) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
clearingFallThroughs = true;
|
clearingFallThroughs = true;
|
||||||
try {
|
try {
|
||||||
boolean fallThroughPreserved = false;
|
boolean fallThroughPreserved = false;
|
||||||
|
@ -894,7 +918,7 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLengthOverridden() {
|
public boolean isLengthOverridden() {
|
||||||
refreshIfNeeded();
|
validate(lock);
|
||||||
return lengthOverride != 0;
|
return lengthOverride != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -911,14 +935,10 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address getDefaultFallThrough() {
|
public Address getDefaultFallThrough() {
|
||||||
lock.acquire();
|
FlowType myFlowType = getFlowType(); // getFlowType will validate
|
||||||
try {
|
|
||||||
// TODO: This used to be in proto. We need to override the proto's flowtype.
|
|
||||||
// This could be pushed back into the proto if we could override the flowType there.
|
|
||||||
FlowType myFlowType = getFlowType();
|
|
||||||
if (myFlowType.hasFallthrough()) {
|
if (myFlowType.hasFallthrough()) {
|
||||||
try {
|
try {
|
||||||
return getAddress().addNoWrap(proto.getFallThroughOffset(this));
|
return address.addNoWrap(getDefaultFallThroughOffset());
|
||||||
}
|
}
|
||||||
catch (AddressOverflowException e) {
|
catch (AddressOverflowException e) {
|
||||||
// ignore
|
// ignore
|
||||||
|
@ -926,15 +946,15 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getDefaultFallThroughOffset() {
|
public int getDefaultFallThroughOffset() {
|
||||||
|
if (proto.getDelaySlotByteCount() <= 0) {
|
||||||
|
return getLength();
|
||||||
|
}
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
|
checkIsValid();
|
||||||
return proto.getFallThroughOffset(this);
|
return proto.getFallThroughOffset(this);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -944,18 +964,11 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasFallthrough() {
|
public boolean hasFallthrough() {
|
||||||
lock.acquire();
|
|
||||||
try {
|
|
||||||
checkIsValid();
|
|
||||||
if (isFallThroughOverridden()) {
|
if (isFallThroughOverridden()) {
|
||||||
return getFallThrough() != null; // fall-through destination stored as reference
|
return getFallThrough() != null; // fall-through destination stored as reference
|
||||||
}
|
}
|
||||||
return getFlowType().hasFallthrough();
|
return getFlowType().hasFallthrough();
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFallthrough() {
|
public boolean isFallthrough() {
|
||||||
|
@ -977,6 +990,7 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ParserContext getParserContext() throws MemoryAccessException {
|
public ParserContext getParserContext() throws MemoryAccessException {
|
||||||
|
// NOTE: It is assumed this is invoked and used within a locked block
|
||||||
if (parserContext == null) {
|
if (parserContext == null) {
|
||||||
parserContext = proto.getParserContext(this, this);
|
parserContext = proto.getParserContext(this, this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,9 +34,10 @@ import ghidra.util.exception.DuplicateNameException;
|
||||||
*/
|
*/
|
||||||
class ArrayDB extends DataTypeDB implements Array {
|
class ArrayDB extends DataTypeDB implements Array {
|
||||||
|
|
||||||
private volatile String displayName;
|
|
||||||
private ArrayDBAdapter adapter;
|
private ArrayDBAdapter adapter;
|
||||||
private int elementLength; // lazy initialization
|
|
||||||
|
private int elementLength = -1; // lazy initialization
|
||||||
|
private String displayName; // lazy initialization
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
|
|
@ -56,11 +56,18 @@ abstract class DataTypeDB extends DatabaseObject implements DataType {
|
||||||
this.dataMgr = dataMgr;
|
this.dataMgr = dataMgr;
|
||||||
this.record = record;
|
this.record = record;
|
||||||
this.lock = dataMgr.lock;
|
this.lock = dataMgr.lock;
|
||||||
refreshName();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the current name so that the next invocation of {@link #getName()} will
|
||||||
|
* force its update via {@link #doGetName()}. It is important that {@link #doGetName()}
|
||||||
|
* does not get invoked during a {@link #refresh()} to avoid problematic recursion during the
|
||||||
|
* refresh caused by recursive use of {@link #checkIsValid()} on the same object.
|
||||||
|
* <P>
|
||||||
|
* NOTE: This must only be invoked while in a locked-state
|
||||||
|
*/
|
||||||
protected void refreshName() {
|
protected void refreshName() {
|
||||||
name = doGetName();
|
name = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -144,9 +151,22 @@ abstract class DataTypeDB extends DatabaseObject implements DataType {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final String getName() {
|
public final String getName() {
|
||||||
validate(lock);
|
String n = name;
|
||||||
|
if (n != null && !isInvalid()) {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
lock.acquire();
|
||||||
|
try {
|
||||||
|
checkIsValid();
|
||||||
|
if (name == null) {
|
||||||
|
name = doGetName();
|
||||||
|
}
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<?> getValueClass(Settings settings) {
|
public Class<?> getValueClass(Settings settings) {
|
||||||
|
|
|
@ -46,6 +46,7 @@ import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.data.DataTypeConflictHandler.ConflictResult;
|
import ghidra.program.model.data.DataTypeConflictHandler.ConflictResult;
|
||||||
import ghidra.program.model.data.Enum;
|
import ghidra.program.model.data.Enum;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
|
import ghidra.program.model.listing.Function;
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
import ghidra.util.classfinder.ClassTranslator;
|
import ghidra.util.classfinder.ClassTranslator;
|
||||||
import ghidra.util.datastruct.FixedSizeHashMap;
|
import ghidra.util.datastruct.FixedSizeHashMap;
|
||||||
|
@ -4129,6 +4130,12 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||||
* @return calling convention name if found else unknown
|
* @return calling convention name if found else unknown
|
||||||
*/
|
*/
|
||||||
public String getCallingConventionName(byte id) {
|
public String getCallingConventionName(byte id) {
|
||||||
|
if (id == DEFAULT_CALLING_CONVENTION_ID) {
|
||||||
|
return Function.DEFAULT_CALLING_CONVENTION_STRING;
|
||||||
|
}
|
||||||
|
else if (id == UNKNOWN_CALLING_CONVENTION_ID) {
|
||||||
|
return CompilerSpec.CALLING_CONVENTION_unknown;
|
||||||
|
}
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
String callingConvention = callingConventionAdapter.getCallingConventionName(id);
|
String callingConvention = callingConventionAdapter.getCallingConventionName(id);
|
||||||
|
|
|
@ -46,11 +46,12 @@ class EnumDB extends DataTypeDB implements Enum {
|
||||||
private EnumDBAdapter adapter;
|
private EnumDBAdapter adapter;
|
||||||
private EnumValueDBAdapter valueAdapter;
|
private EnumValueDBAdapter valueAdapter;
|
||||||
|
|
||||||
private Map<String, Long> nameMap; // name to value
|
// Lazy fields whose initialization is triggered by nameMap=null (see initializeIfNeeded)
|
||||||
private SortedMap<Long, List<String>> valueMap; // value to names
|
private Map<String, Long> nameMap; // lazy initialization, name to value
|
||||||
private Map<String, String> commentMap; // name to comment
|
private SortedMap<Long, List<String>> valueMap; // lazy initialization, value to names
|
||||||
private List<BitGroup> bitGroups;
|
private Map<String, String> commentMap; // lazy initialization, name to comment
|
||||||
private EnumSignedState signedState = null;
|
private List<BitGroup> bitGroups; // lazy initialization
|
||||||
|
private EnumSignedState signedState = null; // lazy initialization
|
||||||
|
|
||||||
EnumDB(DataTypeManagerDB dataMgr, DBObjectCache<DataTypeDB> cache, EnumDBAdapter adapter,
|
EnumDB(DataTypeManagerDB dataMgr, DBObjectCache<DataTypeDB> cache, EnumDBAdapter adapter,
|
||||||
EnumValueDBAdapter valueAdapter, DBRecord record) {
|
EnumValueDBAdapter valueAdapter, DBRecord record) {
|
||||||
|
|
|
@ -37,7 +37,8 @@ class PointerDB extends DataTypeDB implements Pointer {
|
||||||
new SettingsDefinition[] { MutabilitySettingsDefinition.DEF };
|
new SettingsDefinition[] { MutabilitySettingsDefinition.DEF };
|
||||||
|
|
||||||
private PointerDBAdapter adapter;
|
private PointerDBAdapter adapter;
|
||||||
private String displayName;
|
|
||||||
|
private String displayName; // lazy initialization
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>isEquivalentActive</code> is used to break cyclical recursion when
|
* <code>isEquivalentActive</code> is used to break cyclical recursion when
|
||||||
|
|
|
@ -37,7 +37,7 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||||
|
|
||||||
private int structLength;
|
private int structLength;
|
||||||
private int structAlignment; // reflects stored alignment, -1 if not yet stored
|
private int structAlignment; // reflects stored alignment, -1 if not yet stored
|
||||||
private int computedAlignment = -1; // cached alignment if not yet stored
|
private int computedAlignment = -1; // lazy, cached alignment, -1 if not yet computed
|
||||||
|
|
||||||
private int numComponents; // If packed, this does not include the undefined components.
|
private int numComponents; // If packed, this does not include the undefined components.
|
||||||
private List<DataTypeComponentDB> components;
|
private List<DataTypeComponentDB> components;
|
||||||
|
@ -73,7 +73,11 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||||
structLength = record.getIntValue(CompositeDBAdapter.COMPOSITE_LENGTH_COL);
|
structLength = record.getIntValue(CompositeDBAdapter.COMPOSITE_LENGTH_COL);
|
||||||
structAlignment = record.getIntValue(CompositeDBAdapter.COMPOSITE_ALIGNMENT_COL);
|
structAlignment = record.getIntValue(CompositeDBAdapter.COMPOSITE_ALIGNMENT_COL);
|
||||||
computedAlignment = -1;
|
computedAlignment = -1;
|
||||||
numComponents = isPackingEnabled() ? components.size()
|
|
||||||
|
boolean packingDisabled =
|
||||||
|
record.getIntValue(CompositeDBAdapter.COMPOSITE_PACKING_COL) < DEFAULT_PACKING;
|
||||||
|
|
||||||
|
numComponents = !packingDisabled ? components.size()
|
||||||
: record.getIntValue(CompositeDBAdapter.COMPOSITE_NUM_COMPONENTS_COL);
|
: record.getIntValue(CompositeDBAdapter.COMPOSITE_NUM_COMPONENTS_COL);
|
||||||
|
|
||||||
if (oldFlexArrayRecord != null) {
|
if (oldFlexArrayRecord != null) {
|
||||||
|
|
|
@ -35,7 +35,8 @@ import ghidra.util.exception.DuplicateNameException;
|
||||||
class TypedefDB extends DataTypeDB implements TypeDef {
|
class TypedefDB extends DataTypeDB implements TypeDef {
|
||||||
|
|
||||||
private TypedefDBAdapter adapter;
|
private TypedefDBAdapter adapter;
|
||||||
private SettingsDefinition[] settingsDef;
|
|
||||||
|
private SettingsDefinition[] settingsDef; // lazy initialization
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct TypeDefDB instance
|
* Construct TypeDefDB instance
|
||||||
|
|
|
@ -33,7 +33,7 @@ class UnionDB extends CompositeDB implements UnionInternal {
|
||||||
|
|
||||||
private int unionLength;
|
private int unionLength;
|
||||||
private int unionAlignment; // reflects stored alignment, -1 if not yet stored
|
private int unionAlignment; // reflects stored alignment, -1 if not yet stored
|
||||||
private int computedAlignment = -1; // cached alignment if not yet stored
|
private int computedAlignment = -1; // lazy, cached alignment, -1 if not yet computed
|
||||||
|
|
||||||
private List<DataTypeComponentDB> components;
|
private List<DataTypeComponentDB> components;
|
||||||
|
|
||||||
|
|
|
@ -120,34 +120,23 @@ public class FunctionDB extends DatabaseObject implements Function {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isThunk() {
|
public boolean isThunk() {
|
||||||
manager.lock.acquire();
|
validate(manager.lock);
|
||||||
try {
|
|
||||||
checkIsValid();
|
|
||||||
return thunkedFunction != null;
|
return thunkedFunction != null;
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
manager.lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Function getThunkedFunction(boolean recursive) {
|
public Function getThunkedFunction(boolean recursive) {
|
||||||
manager.lock.acquire();
|
validate(manager.lock);
|
||||||
try {
|
FunctionDB localThunkFunc = thunkedFunction;
|
||||||
checkIsValid();
|
if (!recursive || localThunkFunc == null) {
|
||||||
if (!recursive || thunkedFunction == null) {
|
return localThunkFunc;
|
||||||
return thunkedFunction;
|
|
||||||
}
|
}
|
||||||
FunctionDB endFunction = thunkedFunction;
|
FunctionDB endFunction = localThunkFunc;
|
||||||
while (endFunction.thunkedFunction != null) {
|
while ((localThunkFunc = endFunction.thunkedFunction) != null) {
|
||||||
endFunction = endFunction.thunkedFunction;
|
endFunction = localThunkFunc;
|
||||||
}
|
}
|
||||||
return endFunction;
|
return endFunction;
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
manager.lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setThunkedFunction(Function referencedFunction) {
|
public void setThunkedFunction(Function referencedFunction) {
|
||||||
|
@ -332,15 +321,9 @@ public class FunctionDB extends DatabaseObject implements Function {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address getEntryPoint() {
|
public Address getEntryPoint() {
|
||||||
manager.lock.acquire();
|
validate(manager.lock);
|
||||||
try {
|
|
||||||
checkIsValid();
|
|
||||||
return entryPoint;
|
return entryPoint;
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
manager.lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AddressSetView getBody() {
|
public AddressSetView getBody() {
|
||||||
|
@ -378,12 +361,18 @@ public class FunctionDB extends DatabaseObject implements Function {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ReturnParameterDB getReturn() {
|
public ReturnParameterDB getReturn() {
|
||||||
|
validate(manager.lock);
|
||||||
|
FunctionDB localThunkFunc = thunkedFunction;
|
||||||
|
if (localThunkFunc != null) {
|
||||||
|
return localThunkFunc.getReturn();
|
||||||
|
}
|
||||||
|
ReturnParameterDB rp = returnParam;
|
||||||
|
if (rp != null) {
|
||||||
|
return rp;
|
||||||
|
}
|
||||||
manager.lock.acquire();
|
manager.lock.acquire();
|
||||||
try {
|
try {
|
||||||
checkIsValid();
|
// NOTE: lock required to avoid returning null returnParam
|
||||||
if (thunkedFunction != null) {
|
|
||||||
return thunkedFunction.getReturn();
|
|
||||||
}
|
|
||||||
loadVariables();
|
loadVariables();
|
||||||
return returnParam;
|
return returnParam;
|
||||||
}
|
}
|
||||||
|
@ -634,33 +623,23 @@ public class FunctionDB extends DatabaseObject implements Function {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public StackFrame getStackFrame() {
|
public StackFrame getStackFrame() {
|
||||||
manager.lock.acquire();
|
validate(manager.lock);
|
||||||
try {
|
FunctionDB localThunkFunc = thunkedFunction;
|
||||||
checkIsValid();
|
if (localThunkFunc != null) {
|
||||||
if (thunkedFunction != null) {
|
return thunkedFunction.getStackFrame();
|
||||||
return thunkedFunction.frame;
|
|
||||||
}
|
}
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
manager.lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getStackPurgeSize() {
|
public int getStackPurgeSize() {
|
||||||
manager.lock.acquire();
|
validate(manager.lock);
|
||||||
try {
|
FunctionDB localThunkFunc = thunkedFunction;
|
||||||
checkIsValid();
|
if (localThunkFunc != null) {
|
||||||
if (thunkedFunction != null) {
|
return localThunkFunc.getStackPurgeSize();
|
||||||
return thunkedFunction.getStackPurgeSize();
|
|
||||||
}
|
}
|
||||||
return rec.getIntValue(FunctionAdapter.STACK_PURGE_COL);
|
return rec.getIntValue(FunctionAdapter.STACK_PURGE_COL);
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
manager.lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setStackPurgeSize(int change) {
|
public void setStackPurgeSize(int change) {
|
||||||
|
@ -693,20 +672,12 @@ public class FunctionDB extends DatabaseObject implements Function {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isStackPurgeSizeValid() {
|
public boolean isStackPurgeSizeValid() {
|
||||||
manager.lock.acquire();
|
validate(manager.lock);
|
||||||
try {
|
FunctionDB localThunkFunc = thunkedFunction;
|
||||||
checkIsValid();
|
if (localThunkFunc != null) {
|
||||||
if (thunkedFunction != null) {
|
return localThunkFunc.isStackPurgeSizeValid();
|
||||||
return thunkedFunction.isStackPurgeSizeValid();
|
|
||||||
}
|
|
||||||
if (getStackPurgeSize() > 0xffffff) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
manager.lock.release();
|
|
||||||
}
|
}
|
||||||
|
return getStackPurgeSize() <= 0xffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -2417,19 +2388,14 @@ public class FunctionDB extends DatabaseObject implements Function {
|
||||||
* @return true if the indicated flag is set
|
* @return true if the indicated flag is set
|
||||||
*/
|
*/
|
||||||
private boolean isFunctionFlagSet(byte functionFlagIndicator) {
|
private boolean isFunctionFlagSet(byte functionFlagIndicator) {
|
||||||
manager.lock.acquire();
|
validate(manager.lock);
|
||||||
try {
|
FunctionDB localThunkFunc = thunkedFunction;
|
||||||
checkIsValid();
|
if (localThunkFunc != null) {
|
||||||
if (thunkedFunction != null) {
|
return localThunkFunc.isFunctionFlagSet(functionFlagIndicator);
|
||||||
return thunkedFunction.isFunctionFlagSet(functionFlagIndicator);
|
|
||||||
}
|
}
|
||||||
byte flags = rec.getByteValue(FunctionAdapter.FUNCTION_FLAGS_COL);
|
byte flags = rec.getByteValue(FunctionAdapter.FUNCTION_FLAGS_COL);
|
||||||
return ((flags & functionFlagIndicator) != 0);
|
return ((flags & functionFlagIndicator) != 0);
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
manager.lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the indicated function flag to true or false.
|
* Sets the indicated function flag to true or false.
|
||||||
|
@ -2529,29 +2495,20 @@ public class FunctionDB extends DatabaseObject implements Function {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCallingConventionName() {
|
public String getCallingConventionName() {
|
||||||
manager.lock.acquire();
|
if (!validate(manager.lock)) {
|
||||||
try {
|
return UNKNOWN_CALLING_CONVENTION_STRING;
|
||||||
if (!checkIsValid()) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
if (thunkedFunction != null) {
|
FunctionDB localThunkFunc = thunkedFunction;
|
||||||
return thunkedFunction.getCallingConventionName();
|
if (localThunkFunc != null) {
|
||||||
|
return localThunkFunc.getCallingConventionName();
|
||||||
}
|
}
|
||||||
byte callingConventionID = rec.getByteValue(FunctionAdapter.CALLING_CONVENTION_ID_COL);
|
byte callingConventionID = rec.getByteValue(FunctionAdapter.CALLING_CONVENTION_ID_COL);
|
||||||
if (callingConventionID == DataTypeManagerDB.UNKNOWN_CALLING_CONVENTION_ID) {
|
// NOTE: If ID is invalid unknown calling convention name will be returned
|
||||||
return Function.UNKNOWN_CALLING_CONVENTION_STRING;
|
|
||||||
}
|
|
||||||
if (callingConventionID == DataTypeManagerDB.DEFAULT_CALLING_CONVENTION_ID) {
|
|
||||||
return Function.DEFAULT_CALLING_CONVENTION_STRING;
|
|
||||||
}
|
|
||||||
return program.getDataTypeManager().getCallingConventionName(callingConventionID);
|
return program.getDataTypeManager().getCallingConventionName(callingConventionID);
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
manager.lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getRealCallingConventionName() {
|
private String getRealCallingConventionName() {
|
||||||
|
// NOTE: Method only invoked from locked-block
|
||||||
if (thunkedFunction != null) {
|
if (thunkedFunction != null) {
|
||||||
return thunkedFunction.getRealCallingConventionName();
|
return thunkedFunction.getRealCallingConventionName();
|
||||||
}
|
}
|
||||||
|
@ -2651,11 +2608,12 @@ public class FunctionDB extends DatabaseObject implements Function {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCallFixup() {
|
public String getCallFixup() {
|
||||||
manager.lock.acquire();
|
if (!validate(manager.lock)) {
|
||||||
try {
|
return null;
|
||||||
checkIsValid();
|
}
|
||||||
if (thunkedFunction != null) {
|
FunctionDB localThunkFunc = thunkedFunction;
|
||||||
return thunkedFunction.getCallFixup();
|
if (localThunkFunc != null) {
|
||||||
|
return localThunkFunc.getCallFixup();
|
||||||
}
|
}
|
||||||
StringPropertyMap callFixupMap = manager.getCallFixupMap(false);
|
StringPropertyMap callFixupMap = manager.getCallFixupMap(false);
|
||||||
if (callFixupMap == null) {
|
if (callFixupMap == null) {
|
||||||
|
@ -2663,10 +2621,6 @@ public class FunctionDB extends DatabaseObject implements Function {
|
||||||
}
|
}
|
||||||
return callFixupMap.getString(entryPoint);
|
return callFixupMap.getString(entryPoint);
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
manager.lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCallFixup(String name) {
|
public void setCallFixup(String name) {
|
||||||
|
|
|
@ -81,12 +81,6 @@ public class FunctionManagerDB implements FunctionManager {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: use of StringPropertyMap for callFixupMap lacks the ability to listen for changes
|
|
||||||
* which may be made to the map directly (e.g., diff/merge)
|
|
||||||
*/
|
|
||||||
private StringPropertyMap callFixupMap;
|
|
||||||
|
|
||||||
private long lastFuncID = -1;
|
private long lastFuncID = -1;
|
||||||
|
|
||||||
Lock lock;
|
Lock lock;
|
||||||
|
@ -825,7 +819,6 @@ public class FunctionManagerDB implements FunctionManager {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
functionTagManager.invalidateCache();
|
functionTagManager.invalidateCache();
|
||||||
callFixupMap = null;
|
|
||||||
lastFuncID = -1;
|
lastFuncID = -1;
|
||||||
cache.invalidate();
|
cache.invalidate();
|
||||||
}
|
}
|
||||||
|
@ -835,11 +828,8 @@ public class FunctionManagerDB implements FunctionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
StringPropertyMap getCallFixupMap(boolean create) {
|
StringPropertyMap getCallFixupMap(boolean create) {
|
||||||
if (callFixupMap != null) {
|
|
||||||
return callFixupMap;
|
|
||||||
}
|
|
||||||
PropertyMapManager usrPropertyManager = program.getUsrPropertyManager();
|
PropertyMapManager usrPropertyManager = program.getUsrPropertyManager();
|
||||||
callFixupMap = usrPropertyManager.getStringPropertyMap(CALLFIXUP_MAP);
|
StringPropertyMap callFixupMap = usrPropertyManager.getStringPropertyMap(CALLFIXUP_MAP);
|
||||||
if (callFixupMap == null && create) {
|
if (callFixupMap == null && create) {
|
||||||
try {
|
try {
|
||||||
callFixupMap = usrPropertyManager.createStringPropertyMap(CALLFIXUP_MAP);
|
callFixupMap = usrPropertyManager.createStringPropertyMap(CALLFIXUP_MAP);
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
package ghidra.program.database.properties;
|
package ghidra.program.database.properties;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Iterator;
|
import java.util.*;
|
||||||
import java.util.TreeMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import db.*;
|
import db.*;
|
||||||
import ghidra.framework.data.OpenMode;
|
import ghidra.framework.data.OpenMode;
|
||||||
|
@ -49,7 +49,7 @@ public class DBPropertyMapManager implements PropertyMapManager, ManagerDB {
|
||||||
private AddressMap addrMap;
|
private AddressMap addrMap;
|
||||||
private ChangeManager changeMgr;
|
private ChangeManager changeMgr;
|
||||||
private PropertiesDBAdapter propertiesDBAdapter;
|
private PropertiesDBAdapter propertiesDBAdapter;
|
||||||
private TreeMap<String, PropertyMapDB<?>> propertyMapCache;
|
private ConcurrentHashMap<String, PropertyMapDB<?>> propertyMapCache;
|
||||||
private Lock lock;
|
private Lock lock;
|
||||||
|
|
||||||
static final int CURRENT_PROPERTIES_TABLE_VERSION = 0;
|
static final int CURRENT_PROPERTIES_TABLE_VERSION = 0;
|
||||||
|
@ -70,11 +70,9 @@ public class DBPropertyMapManager implements PropertyMapManager, ManagerDB {
|
||||||
static final Schema PROPERTIES_SCHEMA;
|
static final Schema PROPERTIES_SCHEMA;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
|
||||||
PROPERTIES_SCHEMA = new Schema(CURRENT_PROPERTIES_TABLE_VERSION, StringField.INSTANCE,
|
PROPERTIES_SCHEMA = new Schema(CURRENT_PROPERTIES_TABLE_VERSION, StringField.INSTANCE,
|
||||||
"Name", new Field[] { ByteField.INSTANCE, StringField.INSTANCE, IntField.INSTANCE },
|
"Name", new Field[] { ByteField.INSTANCE, StringField.INSTANCE, IntField.INSTANCE },
|
||||||
new String[] { "Type", "Object Class", "Version" });
|
new String[] { "Type", "Object Class", "Version" });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -100,7 +98,7 @@ public class DBPropertyMapManager implements PropertyMapManager, ManagerDB {
|
||||||
dbHandle.createTable(PROPERTIES_TABLE_NAME, PROPERTIES_SCHEMA);
|
dbHandle.createTable(PROPERTIES_TABLE_NAME, PROPERTIES_SCHEMA);
|
||||||
}
|
}
|
||||||
findAdapters(handle);
|
findAdapters(handle);
|
||||||
propertyMapCache = new TreeMap<String, PropertyMapDB<?>>();
|
propertyMapCache = new ConcurrentHashMap<String, PropertyMapDB<?>>();
|
||||||
loadPropertyMaps(openMode, monitor);
|
loadPropertyMaps(openMode, monitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +117,11 @@ public class DBPropertyMapManager implements PropertyMapManager, ManagerDB {
|
||||||
public void invalidateCache(boolean all) throws IOException {
|
public void invalidateCache(boolean all) throws IOException {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
propertyMapCache.clear();
|
for (PropertyMapDB<?> map : propertyMapCache.values()) {
|
||||||
|
map.invalidate();
|
||||||
|
}
|
||||||
|
// NOTE: Reconciling maps immediately allows use to reliably use cache without
|
||||||
|
// requiring map re-validation.
|
||||||
loadPropertyMaps(null, TaskMonitor.DUMMY);
|
loadPropertyMaps(null, TaskMonitor.DUMMY);
|
||||||
}
|
}
|
||||||
catch (CancelledException e) {
|
catch (CancelledException e) {
|
||||||
|
@ -144,12 +146,23 @@ public class DBPropertyMapManager implements PropertyMapManager, ManagerDB {
|
||||||
throws VersionException, CancelledException {
|
throws VersionException, CancelledException {
|
||||||
try {
|
try {
|
||||||
VersionException ve = null;
|
VersionException ve = null;
|
||||||
|
Set<String> oldMapNames = new HashSet<>(propertyMapCache.keySet());
|
||||||
RecordIterator iter = propertiesDBAdapter.getRecords();
|
RecordIterator iter = propertiesDBAdapter.getRecords();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
DBRecord rec = iter.next();
|
DBRecord rec = iter.next();
|
||||||
String name = rec.getKeyField().getString();
|
|
||||||
byte propertyType = rec.getByteValue(PROPERTY_TYPE_COL);
|
byte propertyType = rec.getByteValue(PROPERTY_TYPE_COL);
|
||||||
PropertyMapDB<?> pm = null;
|
String name = rec.getKeyField().getString();
|
||||||
|
oldMapNames.remove(name);
|
||||||
|
|
||||||
|
// Check for pre-existing map
|
||||||
|
PropertyMapDB<?> pm = propertyMapCache.get(name);
|
||||||
|
if (pm != null) {
|
||||||
|
if (pm.validate(lock)) {
|
||||||
|
continue; // keep the map we already have
|
||||||
|
}
|
||||||
|
propertyMapCache.remove(name);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch (propertyType) {
|
switch (propertyType) {
|
||||||
case INT_PROPERTY_TYPE:
|
case INT_PROPERTY_TYPE:
|
||||||
|
@ -208,6 +221,12 @@ public class DBPropertyMapManager implements PropertyMapManager, ManagerDB {
|
||||||
}
|
}
|
||||||
propertyMapCache.put(name, pm);
|
propertyMapCache.put(name, pm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove obsolete maps from cache
|
||||||
|
for (String obsoleteMapName : oldMapNames) {
|
||||||
|
propertyMapCache.remove(obsoleteMapName);
|
||||||
|
}
|
||||||
|
|
||||||
if (ve != null) {
|
if (ve != null) {
|
||||||
throw ve;
|
throw ve;
|
||||||
}
|
}
|
||||||
|
@ -333,7 +352,6 @@ public class DBPropertyMapManager implements PropertyMapManager, ManagerDB {
|
||||||
finally {
|
finally {
|
||||||
lock.release();
|
lock.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -367,7 +385,6 @@ public class DBPropertyMapManager implements PropertyMapManager, ManagerDB {
|
||||||
finally {
|
finally {
|
||||||
lock.release();
|
lock.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -406,7 +423,6 @@ public class DBPropertyMapManager implements PropertyMapManager, ManagerDB {
|
||||||
finally {
|
finally {
|
||||||
lock.release();
|
lock.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -416,15 +432,8 @@ public class DBPropertyMapManager implements PropertyMapManager, ManagerDB {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public PropertyMap<?> getPropertyMap(String propertyName) {
|
public PropertyMap<?> getPropertyMap(String propertyName) {
|
||||||
lock.acquire();
|
|
||||||
try {
|
|
||||||
return propertyMapCache.get(propertyName);
|
return propertyMapCache.get(propertyName);
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the IntPropertyMap associated with the given name.
|
* Returns the IntPropertyMap associated with the given name.
|
||||||
|
@ -434,20 +443,12 @@ public class DBPropertyMapManager implements PropertyMapManager, ManagerDB {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public IntPropertyMap getIntPropertyMap(String propertyName) {
|
public IntPropertyMap getIntPropertyMap(String propertyName) {
|
||||||
|
|
||||||
lock.acquire();
|
|
||||||
try {
|
|
||||||
PropertyMapDB<?> pm = propertyMapCache.get(propertyName);
|
PropertyMapDB<?> pm = propertyMapCache.get(propertyName);
|
||||||
if (pm == null || pm instanceof IntPropertyMap) {
|
if (pm == null || pm instanceof IntPropertyMap) {
|
||||||
return (IntPropertyMap) pm;
|
return (IntPropertyMap) pm;
|
||||||
}
|
}
|
||||||
throw new TypeMismatchException("Property " + propertyName + " is not int type");
|
throw new TypeMismatchException("Property " + propertyName + " is not int type");
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the LongPropertyMap associated with the given name.
|
* Returns the LongPropertyMap associated with the given name.
|
||||||
|
@ -457,19 +458,12 @@ public class DBPropertyMapManager implements PropertyMapManager, ManagerDB {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public LongPropertyMap getLongPropertyMap(String propertyName) {
|
public LongPropertyMap getLongPropertyMap(String propertyName) {
|
||||||
lock.acquire();
|
|
||||||
try {
|
|
||||||
PropertyMapDB<?> pm = propertyMapCache.get(propertyName);
|
PropertyMapDB<?> pm = propertyMapCache.get(propertyName);
|
||||||
if (pm == null || pm instanceof LongPropertyMap) {
|
if (pm == null || pm instanceof LongPropertyMap) {
|
||||||
return (LongPropertyMap) pm;
|
return (LongPropertyMap) pm;
|
||||||
}
|
}
|
||||||
throw new TypeMismatchException("Property " + propertyName + " is not long type");
|
throw new TypeMismatchException("Property " + propertyName + " is not long type");
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the StringPropertyMap associated with the given name.
|
* Returns the StringPropertyMap associated with the given name.
|
||||||
|
@ -479,18 +473,11 @@ public class DBPropertyMapManager implements PropertyMapManager, ManagerDB {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public StringPropertyMap getStringPropertyMap(String propertyName) {
|
public StringPropertyMap getStringPropertyMap(String propertyName) {
|
||||||
lock.acquire();
|
|
||||||
try {
|
|
||||||
PropertyMapDB<?> pm = propertyMapCache.get(propertyName);
|
PropertyMapDB<?> pm = propertyMapCache.get(propertyName);
|
||||||
if (pm == null || pm instanceof StringPropertyMap) {
|
if (pm == null || pm instanceof StringPropertyMap) {
|
||||||
return (StringPropertyMap) pm;
|
return (StringPropertyMap) pm;
|
||||||
}
|
}
|
||||||
throw new TypeMismatchException("Property " + propertyName + " is not String type");
|
throw new TypeMismatchException("Property " + propertyName + " is not String type");
|
||||||
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -501,18 +488,11 @@ public class DBPropertyMapManager implements PropertyMapManager, ManagerDB {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ObjectPropertyMap<?> getObjectPropertyMap(String propertyName) {
|
public ObjectPropertyMap<?> getObjectPropertyMap(String propertyName) {
|
||||||
lock.acquire();
|
|
||||||
try {
|
|
||||||
PropertyMapDB<?> pm = propertyMapCache.get(propertyName);
|
PropertyMapDB<?> pm = propertyMapCache.get(propertyName);
|
||||||
if (pm == null || pm instanceof ObjectPropertyMap) {
|
if (pm == null || pm instanceof ObjectPropertyMap) {
|
||||||
return (ObjectPropertyMap<?>) pm;
|
return (ObjectPropertyMap<?>) pm;
|
||||||
}
|
}
|
||||||
throw new TypeMismatchException("Property " + propertyName + " is not object type");
|
throw new TypeMismatchException("Property " + propertyName + " is not object type");
|
||||||
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -523,18 +503,12 @@ public class DBPropertyMapManager implements PropertyMapManager, ManagerDB {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public VoidPropertyMap getVoidPropertyMap(String propertyName) {
|
public VoidPropertyMap getVoidPropertyMap(String propertyName) {
|
||||||
lock.acquire();
|
|
||||||
try {
|
|
||||||
PropertyMapDB<?> pm = propertyMapCache.get(propertyName);
|
PropertyMapDB<?> pm = propertyMapCache.get(propertyName);
|
||||||
if (pm == null || pm instanceof VoidPropertyMap) {
|
if (pm == null || pm instanceof VoidPropertyMap) {
|
||||||
return (VoidPropertyMap) pm;
|
return (VoidPropertyMap) pm;
|
||||||
}
|
}
|
||||||
throw new TypeMismatchException("Property " + propertyName + " is not Void type");
|
throw new TypeMismatchException("Property " + propertyName + " is not Void type");
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean removePropertyMap(String propertyName) {
|
public boolean removePropertyMap(String propertyName) {
|
||||||
|
@ -564,12 +538,15 @@ public class DBPropertyMapManager implements PropertyMapManager, ManagerDB {
|
||||||
public Iterator<String> propertyManagers() {
|
public Iterator<String> propertyManagers() {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
return propertyMapCache.keySet().iterator();
|
// NOTE: infrequent use expected
|
||||||
|
return propertyMapCache.keySet()
|
||||||
|
.stream()
|
||||||
|
.sorted() // Sort keys in natural order
|
||||||
|
.iterator();
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
lock.release();
|
lock.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -579,7 +556,6 @@ public class DBPropertyMapManager implements PropertyMapManager, ManagerDB {
|
||||||
for (PropertyMapDB<?> pm : propertyMapCache.values()) {
|
for (PropertyMapDB<?> pm : propertyMapCache.values()) {
|
||||||
pm.remove(addr);
|
pm.remove(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
lock.release();
|
lock.release();
|
||||||
|
@ -621,7 +597,6 @@ public class DBPropertyMapManager implements PropertyMapManager, ManagerDB {
|
||||||
public void deleteAddressRange(Address startAddr, Address endAddr, TaskMonitor monitor)
|
public void deleteAddressRange(Address startAddr, Address endAddr, TaskMonitor monitor)
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
removeAll(startAddr, endAddr, monitor);
|
removeAll(startAddr, endAddr, monitor);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package ghidra.program.database.properties;
|
package ghidra.program.database.properties;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import db.*;
|
import db.*;
|
||||||
import db.util.ErrorHandler;
|
import db.util.ErrorHandler;
|
||||||
|
@ -33,6 +34,24 @@ import ghidra.util.task.TaskMonitor;
|
||||||
*/
|
*/
|
||||||
public class IntPropertyMapDB extends PropertyMapDB<Integer> implements IntPropertyMap {
|
public class IntPropertyMapDB extends PropertyMapDB<Integer> implements IntPropertyMap {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single non-capturing lambda record reader function is used to avoid the possibility of
|
||||||
|
* multiple synthetic class instantiations.
|
||||||
|
*/
|
||||||
|
private Function<Long, Integer> valueReader = addrKey -> {
|
||||||
|
Table table = propertyTable;
|
||||||
|
DBRecord rec = null;
|
||||||
|
try {
|
||||||
|
if (table != null) {
|
||||||
|
rec = table.getRecord(addrKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
errHandler.dbError(e);
|
||||||
|
}
|
||||||
|
return rec != null ? rec.getIntValue(PROPERTY_VALUE_COL) : null;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a integer property map.
|
* Construct a integer property map.
|
||||||
* @param dbHandle database handle.
|
* @param dbHandle database handle.
|
||||||
|
@ -58,27 +77,22 @@ public class IntPropertyMapDB extends PropertyMapDB<Integer> implements IntPrope
|
||||||
public void add(Address addr, int value) {
|
public void add(Address addr, int value) {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
|
checkDeleted();
|
||||||
Integer oldValue = null;
|
Integer oldValue = null;
|
||||||
|
long addrKey = addrMap.getKey(addr, true);
|
||||||
long key = addrMap.getKey(addr, true);
|
|
||||||
|
|
||||||
if (propertyTable == null) {
|
if (propertyTable == null) {
|
||||||
createTable(IntField.INSTANCE);
|
createTable(IntField.INSTANCE);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
oldValue = (Integer) cache.get(key);
|
oldValue = cache.get(addrKey);
|
||||||
if (oldValue == null) {
|
if (oldValue == null) {
|
||||||
DBRecord rec = propertyTable.getRecord(key);
|
oldValue = valueReader.apply(addrKey);
|
||||||
if (rec != null) {
|
|
||||||
oldValue = rec.getIntValue(PROPERTY_VALUE_COL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
DBRecord rec = schema.createRecord(addrKey);
|
||||||
DBRecord rec = schema.createRecord(key);
|
|
||||||
|
|
||||||
rec.setIntValue(PROPERTY_VALUE_COL, value);
|
rec.setIntValue(PROPERTY_VALUE_COL, value);
|
||||||
propertyTable.putRecord(rec);
|
propertyTable.putRecord(rec);
|
||||||
cache.put(key, value);
|
cache.put(addrKey, value);
|
||||||
|
|
||||||
changeMgr.setPropertyChanged(name, addr, oldValue, value);
|
changeMgr.setPropertyChanged(name, addr, oldValue, value);
|
||||||
}
|
}
|
||||||
|
@ -92,44 +106,25 @@ public class IntPropertyMapDB extends PropertyMapDB<Integer> implements IntPrope
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getInt(Address addr) throws NoValueException {
|
public int getInt(Address addr) throws NoValueException {
|
||||||
if (propertyTable == null) {
|
Integer value = get(addr);
|
||||||
|
if (value == null) {
|
||||||
throw NO_VALUE_EXCEPTION;
|
throw NO_VALUE_EXCEPTION;
|
||||||
}
|
}
|
||||||
|
return value;
|
||||||
lock.acquire();
|
|
||||||
try {
|
|
||||||
long key = addrMap.getKey(addr, false);
|
|
||||||
if (key == AddressMap.INVALID_ADDRESS_KEY) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
Object obj = cache.get(key);
|
|
||||||
if (obj != null) {
|
|
||||||
return ((Integer) obj).intValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
DBRecord rec = propertyTable.getRecord(key);
|
|
||||||
if (rec == null) {
|
|
||||||
throw NO_VALUE_EXCEPTION;
|
|
||||||
}
|
|
||||||
return rec.getIntValue(PROPERTY_VALUE_COL);
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
errHandler.dbError(e);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer get(Address addr) {
|
public Integer get(Address addr) {
|
||||||
try {
|
validate(lock);
|
||||||
return getInt(addr);
|
Table table = propertyTable;
|
||||||
}
|
if (table == null) {
|
||||||
catch (NoValueException e) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
long addrKey = addrMap.getKey(addr, false);
|
||||||
|
if (addrKey == AddressMap.INVALID_ADDRESS_KEY) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return cache.computeIfAbsent(addrKey, valueReader);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package ghidra.program.database.properties;
|
package ghidra.program.database.properties;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import db.*;
|
import db.*;
|
||||||
import db.util.ErrorHandler;
|
import db.util.ErrorHandler;
|
||||||
|
@ -33,6 +34,24 @@ import ghidra.util.task.TaskMonitor;
|
||||||
*/
|
*/
|
||||||
public class LongPropertyMapDB extends PropertyMapDB<Long> implements LongPropertyMap {
|
public class LongPropertyMapDB extends PropertyMapDB<Long> implements LongPropertyMap {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single record reader function is used to avoid the use of a lambda form which could
|
||||||
|
* cause multiple synthetic class instantiations.
|
||||||
|
*/
|
||||||
|
private Function<Long, Long> valueReader = addrKey -> {
|
||||||
|
Table table = propertyTable;
|
||||||
|
DBRecord rec = null;
|
||||||
|
try {
|
||||||
|
if (table != null) {
|
||||||
|
rec = table.getRecord(addrKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
errHandler.dbError(e);
|
||||||
|
}
|
||||||
|
return rec != null ? rec.getLongValue(PROPERTY_VALUE_COL) : null;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a long property map.
|
* Construct a long property map.
|
||||||
* @param dbHandle database handle.
|
* @param dbHandle database handle.
|
||||||
|
@ -56,26 +75,24 @@ public class LongPropertyMapDB extends PropertyMapDB<Long> implements LongProper
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(Address addr, long value) {
|
public void add(Address addr, long value) {
|
||||||
Long oldValue = null;
|
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
long key = addrMap.getKey(addr, true);
|
checkDeleted();
|
||||||
|
Long oldValue = null;
|
||||||
|
long addrKey = addrMap.getKey(addr, true);
|
||||||
if (propertyTable == null) {
|
if (propertyTable == null) {
|
||||||
createTable(LongField.INSTANCE);
|
createTable(LongField.INSTANCE);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
oldValue = (Long) cache.get(key);
|
oldValue = cache.get(addrKey);
|
||||||
if (oldValue == null) {
|
if (oldValue == null) {
|
||||||
DBRecord rec = propertyTable.getRecord(key);
|
oldValue = valueReader.apply(addrKey);
|
||||||
if (rec != null) {
|
|
||||||
oldValue = rec.getLongValue(PROPERTY_VALUE_COL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
DBRecord rec = schema.createRecord(addrKey);
|
||||||
DBRecord rec = schema.createRecord(key);
|
|
||||||
rec.setLongValue(PROPERTY_VALUE_COL, value);
|
rec.setLongValue(PROPERTY_VALUE_COL, value);
|
||||||
propertyTable.putRecord(rec);
|
propertyTable.putRecord(rec);
|
||||||
cache.put(key, value);
|
cache.put(addrKey, value);
|
||||||
changeMgr.setPropertyChanged(name, addr, oldValue, value);
|
changeMgr.setPropertyChanged(name, addr, oldValue, value);
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
|
@ -89,44 +106,25 @@ public class LongPropertyMapDB extends PropertyMapDB<Long> implements LongProper
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getLong(Address addr) throws NoValueException {
|
public long getLong(Address addr) throws NoValueException {
|
||||||
if (propertyTable == null) {
|
Long value = get(addr);
|
||||||
|
if (value == null) {
|
||||||
throw NO_VALUE_EXCEPTION;
|
throw NO_VALUE_EXCEPTION;
|
||||||
}
|
}
|
||||||
|
return value;
|
||||||
lock.acquire();
|
|
||||||
try {
|
|
||||||
long key = addrMap.getKey(addr, false);
|
|
||||||
if (key == AddressMap.INVALID_ADDRESS_KEY) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
Object obj = cache.get(key);
|
|
||||||
if (obj != null) {
|
|
||||||
return ((Long) obj).longValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
DBRecord rec = propertyTable.getRecord(key);
|
|
||||||
if (rec == null) {
|
|
||||||
throw NO_VALUE_EXCEPTION;
|
|
||||||
}
|
|
||||||
return rec.getLongValue(PROPERTY_VALUE_COL);
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
errHandler.dbError(e);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long get(Address addr) {
|
public Long get(Address addr) {
|
||||||
try {
|
validate(lock);
|
||||||
return getLong(addr);
|
Table table = propertyTable;
|
||||||
}
|
if (table == null) {
|
||||||
catch (NoValueException e) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
long addrKey = addrMap.getKey(addr, false);
|
||||||
|
if (addrKey == AddressMap.INVALID_ADDRESS_KEY) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return cache.computeIfAbsent(addrKey, valueReader);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package ghidra.program.database.properties;
|
package ghidra.program.database.properties;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import db.*;
|
import db.*;
|
||||||
import db.util.ErrorHandler;
|
import db.util.ErrorHandler;
|
||||||
|
@ -42,6 +43,44 @@ public class ObjectPropertyMapDB<T extends Saveable> extends PropertyMapDB<T>
|
||||||
private int saveableObjectVersion;
|
private int saveableObjectVersion;
|
||||||
private boolean supportsPrivate;
|
private boolean supportsPrivate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single non-capturing lambda record reader function is used to avoid the possibility of
|
||||||
|
* multiple synthetic class instantiations.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private Function<Long, T> valueReader = addrKey -> {
|
||||||
|
Table table = propertyTable;
|
||||||
|
DBRecord rec = null;
|
||||||
|
try {
|
||||||
|
if (table != null) {
|
||||||
|
rec = table.getRecord(addrKey);
|
||||||
|
}
|
||||||
|
if (rec == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ObjectStorageAdapterDB objStorage = new ObjectStorageAdapterDB(rec);
|
||||||
|
if (saveableObjectClass == GenericSaveable.class) {
|
||||||
|
return (T) new GenericSaveable(rec, propertyTable.getSchema());
|
||||||
|
}
|
||||||
|
T obj = saveableObjectClass.getDeclaredConstructor().newInstance();
|
||||||
|
obj.restore(objStorage);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
errHandler.dbError(e);
|
||||||
|
}
|
||||||
|
catch (RuntimeException e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
catch (InstantiationException e) {
|
||||||
|
errHandler.dbError(new IOException("Could not instantiate " + e.getMessage()));
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
errHandler.dbError(new IOException(e.getMessage()));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct an Saveable object property map.
|
* Construct an Saveable object property map.
|
||||||
* @param dbHandle database handle.
|
* @param dbHandle database handle.
|
||||||
|
@ -256,11 +295,19 @@ public class ObjectPropertyMapDB<T extends Saveable> extends PropertyMapDB<T>
|
||||||
public void add(Address addr, T value) {
|
public void add(Address addr, T value) {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
|
checkDeleted();
|
||||||
if (!saveableObjectClass.isAssignableFrom(value.getClass())) {
|
if (!saveableObjectClass.isAssignableFrom(value.getClass())) {
|
||||||
throw new IllegalArgumentException("value is not " + saveableObjectClass.getName());
|
throw new IllegalArgumentException("value is not " + saveableObjectClass.getName());
|
||||||
}
|
}
|
||||||
long key = addrMap.getKey(addr, true);
|
long addrKey = addrMap.getKey(addr, true);
|
||||||
T oldValue = get(addr);
|
|
||||||
|
T oldValue = null;
|
||||||
|
if (propertyTable != null) {
|
||||||
|
oldValue = cache.get(addrKey);
|
||||||
|
if (oldValue == null) {
|
||||||
|
oldValue = valueReader.apply(addrKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String tableName = getTableName();
|
String tableName = getTableName();
|
||||||
Schema s;
|
Schema s;
|
||||||
|
@ -271,7 +318,7 @@ public class ObjectPropertyMapDB<T extends Saveable> extends PropertyMapDB<T>
|
||||||
s = objStorage.getSchema(value.getSchemaVersion());
|
s = objStorage.getSchema(value.getSchemaVersion());
|
||||||
checkSchema(s);
|
checkSchema(s);
|
||||||
createPropertyTable(tableName, s);
|
createPropertyTable(tableName, s);
|
||||||
rec = schema.createRecord(key);
|
rec = schema.createRecord(addrKey);
|
||||||
objStorage.save(rec);
|
objStorage.save(rec);
|
||||||
}
|
}
|
||||||
else { // GenericSaveable
|
else { // GenericSaveable
|
||||||
|
@ -281,11 +328,11 @@ public class ObjectPropertyMapDB<T extends Saveable> extends PropertyMapDB<T>
|
||||||
checkSchema(s);
|
checkSchema(s);
|
||||||
createPropertyTable(tableName, s);
|
createPropertyTable(tableName, s);
|
||||||
rec = originalRec.copy();
|
rec = originalRec.copy();
|
||||||
rec.setKey(key);
|
rec.setKey(addrKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
propertyTable.putRecord(rec);
|
propertyTable.putRecord(rec);
|
||||||
cache.put(key, value);
|
cache.put(addrKey, value);
|
||||||
|
|
||||||
if (!isPrivate(value)) {
|
if (!isPrivate(value)) {
|
||||||
changeMgr.setPropertyChanged(name, addr, oldValue, value);
|
changeMgr.setPropertyChanged(name, addr, oldValue, value);
|
||||||
|
@ -326,57 +373,18 @@ public class ObjectPropertyMapDB<T extends Saveable> extends PropertyMapDB<T>
|
||||||
return saveableObjectClass;
|
return saveableObjectClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
@Override
|
||||||
public T get(Address addr) {
|
public T get(Address addr) {
|
||||||
if (propertyTable == null) {
|
validate(lock);
|
||||||
|
Table table = propertyTable;
|
||||||
|
if (table == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
long addrKey = addrMap.getKey(addr, false);
|
||||||
T obj = null;
|
if (addrKey == AddressMap.INVALID_ADDRESS_KEY) {
|
||||||
|
|
||||||
lock.acquire();
|
|
||||||
try {
|
|
||||||
long key = addrMap.getKey(addr, false);
|
|
||||||
if (key == AddressMap.INVALID_ADDRESS_KEY) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
obj = (T) cache.get(key);
|
return cache.computeIfAbsent(addrKey, valueReader);
|
||||||
if (obj != null) {
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
DBRecord rec = propertyTable.getRecord(key);
|
|
||||||
if (rec == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
ObjectStorageAdapterDB objStorage = new ObjectStorageAdapterDB(rec);
|
|
||||||
if (saveableObjectClass == GenericSaveable.class) {
|
|
||||||
obj = (T) new GenericSaveable(rec, propertyTable.getSchema());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
obj = saveableObjectClass.getDeclaredConstructor().newInstance();
|
|
||||||
obj.restore(objStorage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
errHandler.dbError(e);
|
|
||||||
}
|
|
||||||
catch (RuntimeException e) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
catch (InstantiationException e) {
|
|
||||||
errHandler.dbError(new IOException("Could not instantiate " + e.getMessage()));
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
errHandler.dbError(new IOException(e.getMessage()));
|
|
||||||
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -21,6 +21,7 @@ import java.util.NoSuchElementException;
|
||||||
import db.*;
|
import db.*;
|
||||||
import db.util.ErrorHandler;
|
import db.util.ErrorHandler;
|
||||||
import ghidra.framework.data.OpenMode;
|
import ghidra.framework.data.OpenMode;
|
||||||
|
import ghidra.program.database.DatabaseObject;
|
||||||
import ghidra.program.database.map.*;
|
import ghidra.program.database.map.*;
|
||||||
import ghidra.program.database.util.DatabaseTableUtils;
|
import ghidra.program.database.util.DatabaseTableUtils;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
|
@ -37,7 +38,7 @@ import ghidra.util.task.TaskMonitor;
|
||||||
* The map is stored within a database table.
|
* The map is stored within a database table.
|
||||||
* @param <T> property value type
|
* @param <T> property value type
|
||||||
*/
|
*/
|
||||||
public abstract class PropertyMapDB<T> implements PropertyMap<T> {
|
public abstract class PropertyMapDB<T> extends DatabaseObject implements PropertyMap<T> {
|
||||||
|
|
||||||
private static final String PROPERTY_TABLE_PREFIX = "Property Map - ";
|
private static final String PROPERTY_TABLE_PREFIX = "Property Map - ";
|
||||||
|
|
||||||
|
@ -63,7 +64,7 @@ public abstract class PropertyMapDB<T> implements PropertyMap<T> {
|
||||||
protected AddressMap addrMap;
|
protected AddressMap addrMap;
|
||||||
protected String name;
|
protected String name;
|
||||||
|
|
||||||
protected ObjectCache cache = new ObjectCache(DEFAULT_CACHE_SIZE);
|
protected ObjectCache<T> cache = new ObjectCache<>(DEFAULT_CACHE_SIZE);
|
||||||
protected Lock lock;
|
protected Lock lock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -76,6 +77,7 @@ public abstract class PropertyMapDB<T> implements PropertyMap<T> {
|
||||||
*/
|
*/
|
||||||
PropertyMapDB(DBHandle dbHandle, ErrorHandler errHandler, ChangeManager changeMgr,
|
PropertyMapDB(DBHandle dbHandle, ErrorHandler errHandler, ChangeManager changeMgr,
|
||||||
AddressMap addrMap, String name) {
|
AddressMap addrMap, String name) {
|
||||||
|
super(null, 0); // DatabaseObject cache is not used
|
||||||
|
|
||||||
this.dbHandle = dbHandle;
|
this.dbHandle = dbHandle;
|
||||||
this.errHandler = errHandler;
|
this.errHandler = errHandler;
|
||||||
|
@ -92,6 +94,12 @@ public abstract class PropertyMapDB<T> implements PropertyMap<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Expose validate method to DBPropertyMapManager
|
||||||
|
@Override
|
||||||
|
protected boolean validate(Lock lck) {
|
||||||
|
return super.validate(lck);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a table upgrade should be performed or a version error thrown.
|
* Check if a table upgrade should be performed or a version error thrown.
|
||||||
* @param openMode the mode that the program was openned in or null if instantiated during
|
* @param openMode the mode that the program was openned in or null if instantiated during
|
||||||
|
@ -180,22 +188,24 @@ public abstract class PropertyMapDB<T> implements PropertyMap<T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the default propertyTable.
|
* Create the default propertyTable.
|
||||||
* This method may be called by add property methods if propertyTable
|
* This method may be called by add property methods if propertyTable is null.
|
||||||
* is null.
|
* @param valueField property value field type (null corresponds to void map table)
|
||||||
* @param valueField property value field type
|
|
||||||
* @throws IOException if IO error occurs
|
* @throws IOException if IO error occurs
|
||||||
*/
|
*/
|
||||||
protected void createTable(Field valueField) throws IOException {
|
protected void createTable(Field valueField) throws IOException {
|
||||||
|
schema = getTableSchema(valueField);
|
||||||
|
propertyTable = dbHandle.createTable(getTableName(), schema);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Schema getTableSchema(Field valueField) {
|
||||||
if (valueField != null) {
|
if (valueField != null) {
|
||||||
// Create default table schema with a value column and an long Address key
|
// Create default table schema with a value column and an long Address key
|
||||||
Field[] fields = new Field[] { valueField };
|
Field[] fields = new Field[] { valueField };
|
||||||
schema = new Schema(0, "Address", fields, SCHEMA_FIELD_NAMES);
|
return new Schema(0, "Address", fields, SCHEMA_FIELD_NAMES);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// Table contains only a long Address key
|
// Table contains only a long Address key (i.e., void property map)
|
||||||
schema = new Schema(0, "Address", NO_SCHEMA_FIELDS, NO_SCHEMA_FIELD_NAMES);
|
return new Schema(0, "Address", NO_SCHEMA_FIELDS, NO_SCHEMA_FIELD_NAMES);
|
||||||
}
|
|
||||||
propertyTable = dbHandle.createTable(getTableName(), schema);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -227,8 +237,10 @@ public abstract class PropertyMapDB<T> implements PropertyMap<T> {
|
||||||
public void delete() throws IOException {
|
public void delete() throws IOException {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
|
checkDeleted();
|
||||||
|
setDeleted();
|
||||||
if (propertyTable != null) {
|
if (propertyTable != null) {
|
||||||
cache = null;
|
cache = new ObjectCache<>(DEFAULT_CACHE_SIZE);
|
||||||
dbHandle.deleteTable(getTableName());
|
dbHandle.deleteTable(getTableName());
|
||||||
propertyTable = null;
|
propertyTable = null;
|
||||||
}
|
}
|
||||||
|
@ -240,12 +252,14 @@ public abstract class PropertyMapDB<T> implements PropertyMap<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean intersects(Address startAddr, Address endAddr) {
|
public boolean intersects(Address startAddr, Address endAddr) {
|
||||||
if (propertyTable == null) {
|
validate(lock);
|
||||||
|
Table table = propertyTable;
|
||||||
|
if (table == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
AddressKeyIterator iter =
|
AddressKeyIterator iter =
|
||||||
new AddressKeyIterator(propertyTable, addrMap, startAddr, endAddr, startAddr, true);
|
new AddressKeyIterator(table, addrMap, startAddr, endAddr, startAddr, true);
|
||||||
return iter.hasNext();
|
return iter.hasNext();
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
|
@ -256,12 +270,14 @@ public abstract class PropertyMapDB<T> implements PropertyMap<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean intersects(AddressSetView set) {
|
public boolean intersects(AddressSetView set) {
|
||||||
if (propertyTable == null) {
|
validate(lock);
|
||||||
|
Table table = propertyTable;
|
||||||
|
if (table == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
AddressKeyIterator iter =
|
AddressKeyIterator iter =
|
||||||
new AddressKeyIterator(propertyTable, addrMap, set, set.getMinAddress(), true);
|
new AddressKeyIterator(table, addrMap, set, set.getMinAddress(), true);
|
||||||
return iter.hasNext();
|
return iter.hasNext();
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
|
@ -272,13 +288,14 @@ public abstract class PropertyMapDB<T> implements PropertyMap<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean removeRange(Address startAddr, Address endAddr) {
|
public boolean removeRange(Address startAddr, Address endAddr) {
|
||||||
|
lock.acquire();
|
||||||
|
try {
|
||||||
|
checkDeleted();
|
||||||
if (propertyTable == null) {
|
if (propertyTable == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
lock.acquire();
|
|
||||||
try {
|
|
||||||
if (AddressRecordDeleter.deleteRecords(propertyTable, addrMap, startAddr, endAddr)) {
|
if (AddressRecordDeleter.deleteRecords(propertyTable, addrMap, startAddr, endAddr)) {
|
||||||
cache = new ObjectCache(DEFAULT_CACHE_SIZE);
|
cache = new ObjectCache<>(DEFAULT_CACHE_SIZE);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -293,15 +310,16 @@ public abstract class PropertyMapDB<T> implements PropertyMap<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean remove(Address addr) {
|
public boolean remove(Address addr) {
|
||||||
if (propertyTable == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
boolean result = false;
|
boolean result = false;
|
||||||
try {
|
try {
|
||||||
long key = addrMap.getKey(addr, false);
|
checkDeleted();
|
||||||
cache.remove(key);
|
if (propertyTable == null) {
|
||||||
result = propertyTable.deleteRecord(key);
|
return false;
|
||||||
|
}
|
||||||
|
long addrKey = addrMap.getKey(addr, false);
|
||||||
|
cache.remove(addrKey);
|
||||||
|
result = propertyTable.deleteRecord(addrKey);
|
||||||
changeMgr.setPropertyChanged(name, addr, null, null);
|
changeMgr.setPropertyChanged(name, addr, null, null);
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
|
@ -315,33 +333,32 @@ public abstract class PropertyMapDB<T> implements PropertyMap<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasProperty(Address addr) {
|
public boolean hasProperty(Address addr) {
|
||||||
if (propertyTable == null) {
|
validate(lock);
|
||||||
|
Table table = propertyTable;
|
||||||
|
if (table == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
lock.acquire();
|
|
||||||
boolean result = false;
|
|
||||||
try {
|
try {
|
||||||
long key = addrMap.getKey(addr, false);
|
long addrKey = addrMap.getKey(addr, false);
|
||||||
if (key != AddressMap.INVALID_ADDRESS_KEY) {
|
if (addrKey != AddressMap.INVALID_ADDRESS_KEY) {
|
||||||
result = cache.contains(key) || propertyTable.hasRecord(key);
|
return cache.contains(addrKey) || table.hasRecord(addrKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
errHandler.dbError(e);
|
errHandler.dbError(e);
|
||||||
}
|
}
|
||||||
finally {
|
return false;
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address getNextPropertyAddress(Address addr) {
|
public Address getNextPropertyAddress(Address addr) {
|
||||||
if (propertyTable == null) {
|
validate(lock);
|
||||||
|
Table table = propertyTable;
|
||||||
|
if (table == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
AddressKeyIterator iter = new AddressKeyIterator(propertyTable, addrMap, addr, false);
|
AddressKeyIterator iter = new AddressKeyIterator(table, addrMap, addr, false);
|
||||||
return addrMap.decodeAddress(iter.next());
|
return addrMap.decodeAddress(iter.next());
|
||||||
}
|
}
|
||||||
catch (NoSuchElementException e) {
|
catch (NoSuchElementException e) {
|
||||||
|
@ -355,11 +372,13 @@ public abstract class PropertyMapDB<T> implements PropertyMap<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address getPreviousPropertyAddress(Address addr) {
|
public Address getPreviousPropertyAddress(Address addr) {
|
||||||
if (propertyTable == null) {
|
validate(lock);
|
||||||
|
Table table = propertyTable;
|
||||||
|
if (table == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
AddressKeyIterator iter = new AddressKeyIterator(propertyTable, addrMap, addr, true);
|
AddressKeyIterator iter = new AddressKeyIterator(table, addrMap, addr, true);
|
||||||
return addrMap.decodeAddress(iter.previous());
|
return addrMap.decodeAddress(iter.previous());
|
||||||
}
|
}
|
||||||
catch (NoSuchElementException e) {
|
catch (NoSuchElementException e) {
|
||||||
|
@ -373,11 +392,13 @@ public abstract class PropertyMapDB<T> implements PropertyMap<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address getFirstPropertyAddress() {
|
public Address getFirstPropertyAddress() {
|
||||||
if (propertyTable == null) {
|
validate(lock);
|
||||||
|
Table table = propertyTable;
|
||||||
|
if (table == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
AddressKeyIterator iter = new AddressKeyIterator(propertyTable, addrMap, true);
|
AddressKeyIterator iter = new AddressKeyIterator(table, addrMap, true);
|
||||||
return addrMap.decodeAddress(iter.next());
|
return addrMap.decodeAddress(iter.next());
|
||||||
}
|
}
|
||||||
catch (NoSuchElementException e) {
|
catch (NoSuchElementException e) {
|
||||||
|
@ -391,11 +412,13 @@ public abstract class PropertyMapDB<T> implements PropertyMap<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address getLastPropertyAddress() {
|
public Address getLastPropertyAddress() {
|
||||||
if (propertyTable == null) {
|
validate(lock);
|
||||||
|
Table table = propertyTable;
|
||||||
|
if (table == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
AddressKeyIterator iter = new AddressKeyIterator(propertyTable, addrMap,
|
AddressKeyIterator iter = new AddressKeyIterator(table, addrMap,
|
||||||
addrMap.getAddressFactory().getAddressSet().getMaxAddress(), false);
|
addrMap.getAddressFactory().getAddressSet().getMaxAddress(), false);
|
||||||
return addrMap.decodeAddress(iter.previous());
|
return addrMap.decodeAddress(iter.previous());
|
||||||
}
|
}
|
||||||
|
@ -410,7 +433,9 @@ public abstract class PropertyMapDB<T> implements PropertyMap<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
return propertyTable != null ? propertyTable.getRecordCount() : 0;
|
validate(lock);
|
||||||
|
Table table = propertyTable;
|
||||||
|
return table != null ? table.getRecordCount() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -423,13 +448,15 @@ public abstract class PropertyMapDB<T> implements PropertyMap<T> {
|
||||||
*/
|
*/
|
||||||
public AddressKeyIterator getAddressKeyIterator(AddressSetView set, boolean atStart)
|
public AddressKeyIterator getAddressKeyIterator(AddressSetView set, boolean atStart)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (propertyTable == null || (set != null && set.isEmpty())) {
|
validate(lock);
|
||||||
|
Table table = propertyTable;
|
||||||
|
if (table == null || (set != null && set.isEmpty())) {
|
||||||
return AddressKeyIterator.EMPTY_ITERATOR;
|
return AddressKeyIterator.EMPTY_ITERATOR;
|
||||||
}
|
}
|
||||||
if (atStart) {
|
if (atStart) {
|
||||||
return new AddressKeyIterator(propertyTable, addrMap, set, set.getMinAddress(), true);
|
return new AddressKeyIterator(table, addrMap, set, set.getMinAddress(), true);
|
||||||
}
|
}
|
||||||
return new AddressKeyIterator(propertyTable, addrMap, set, set.getMaxAddress(), false);
|
return new AddressKeyIterator(table, addrMap, set, set.getMaxAddress(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -441,11 +468,12 @@ public abstract class PropertyMapDB<T> implements PropertyMap<T> {
|
||||||
*/
|
*/
|
||||||
public AddressKeyIterator getAddressKeyIterator(Address start, boolean before)
|
public AddressKeyIterator getAddressKeyIterator(Address start, boolean before)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
validate(lock);
|
||||||
if (propertyTable == null) {
|
Table table = propertyTable;
|
||||||
|
if (table == null) {
|
||||||
return AddressKeyIterator.EMPTY_ITERATOR;
|
return AddressKeyIterator.EMPTY_ITERATOR;
|
||||||
}
|
}
|
||||||
return new AddressKeyIterator(propertyTable, addrMap, start, before);
|
return new AddressKeyIterator(table, addrMap, start, before);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -459,14 +487,15 @@ public abstract class PropertyMapDB<T> implements PropertyMap<T> {
|
||||||
*/
|
*/
|
||||||
public AddressKeyIterator getAddressKeyIterator(Address start, Address end, boolean atStart)
|
public AddressKeyIterator getAddressKeyIterator(Address start, Address end, boolean atStart)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
validate(lock);
|
||||||
if (propertyTable == null) {
|
Table table = propertyTable;
|
||||||
|
if (table == null) {
|
||||||
return AddressKeyIterator.EMPTY_ITERATOR;
|
return AddressKeyIterator.EMPTY_ITERATOR;
|
||||||
}
|
}
|
||||||
if (atStart) {
|
if (atStart) {
|
||||||
return new AddressKeyIterator(propertyTable, addrMap, start, end, start, true);
|
return new AddressKeyIterator(table, addrMap, start, end, start, true);
|
||||||
}
|
}
|
||||||
return new AddressKeyIterator(propertyTable, addrMap, start, end, end, false);
|
return new AddressKeyIterator(table, addrMap, start, end, end, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -495,12 +524,14 @@ public abstract class PropertyMapDB<T> implements PropertyMap<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AddressIterator getPropertyIterator() {
|
public AddressIterator getPropertyIterator() {
|
||||||
if (propertyTable == null) {
|
validate(lock);
|
||||||
|
Table table = propertyTable;
|
||||||
|
if (table == null) {
|
||||||
return new EmptyAddressIterator();
|
return new EmptyAddressIterator();
|
||||||
}
|
}
|
||||||
AddressKeyIterator keyIter = null;
|
AddressKeyIterator keyIter = null;
|
||||||
try {
|
try {
|
||||||
keyIter = new AddressKeyIterator(propertyTable, addrMap, true);
|
keyIter = new AddressKeyIterator(table, addrMap, true);
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
errHandler.dbError(e);
|
errHandler.dbError(e);
|
||||||
|
@ -510,13 +541,14 @@ public abstract class PropertyMapDB<T> implements PropertyMap<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AddressIterator getPropertyIterator(AddressSetView asv) {
|
public AddressIterator getPropertyIterator(AddressSetView asv) {
|
||||||
if (propertyTable == null) {
|
validate(lock);
|
||||||
|
Table table = propertyTable;
|
||||||
|
if (table == null) {
|
||||||
return new EmptyAddressIterator();
|
return new EmptyAddressIterator();
|
||||||
}
|
}
|
||||||
AddressKeyIterator keyIter = null;
|
AddressKeyIterator keyIter = null;
|
||||||
try {
|
try {
|
||||||
keyIter =
|
keyIter = new AddressKeyIterator(table, addrMap, asv, asv.getMinAddress(), true);
|
||||||
new AddressKeyIterator(propertyTable, addrMap, asv, asv.getMinAddress(), true);
|
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
errHandler.dbError(e);
|
errHandler.dbError(e);
|
||||||
|
@ -526,18 +558,18 @@ public abstract class PropertyMapDB<T> implements PropertyMap<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AddressIterator getPropertyIterator(AddressSetView asv, boolean forward) {
|
public AddressIterator getPropertyIterator(AddressSetView asv, boolean forward) {
|
||||||
if (propertyTable == null || (asv != null && asv.isEmpty())) {
|
validate(lock);
|
||||||
|
Table table = propertyTable;
|
||||||
|
if (table == null || (asv != null && asv.isEmpty())) {
|
||||||
return AddressIterator.EMPTY_ITERATOR;
|
return AddressIterator.EMPTY_ITERATOR;
|
||||||
}
|
}
|
||||||
AddressKeyIterator keyIter = null;
|
AddressKeyIterator keyIter = null;
|
||||||
try {
|
try {
|
||||||
if (forward) {
|
if (forward) {
|
||||||
keyIter =
|
keyIter = new AddressKeyIterator(table, addrMap, asv, asv.getMinAddress(), true);
|
||||||
new AddressKeyIterator(propertyTable, addrMap, asv, asv.getMinAddress(), true);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
keyIter =
|
keyIter = new AddressKeyIterator(table, addrMap, asv, asv.getMaxAddress(), false);
|
||||||
new AddressKeyIterator(propertyTable, addrMap, asv, asv.getMaxAddress(), false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
|
@ -548,12 +580,14 @@ public abstract class PropertyMapDB<T> implements PropertyMap<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AddressIterator getPropertyIterator(Address start, boolean forward) {
|
public AddressIterator getPropertyIterator(Address start, boolean forward) {
|
||||||
if (propertyTable == null) {
|
validate(lock);
|
||||||
|
Table table = propertyTable;
|
||||||
|
if (table == null) {
|
||||||
return new EmptyAddressIterator();
|
return new EmptyAddressIterator();
|
||||||
}
|
}
|
||||||
AddressKeyIterator keyIter = null;
|
AddressKeyIterator keyIter = null;
|
||||||
try {
|
try {
|
||||||
keyIter = new AddressKeyIterator(propertyTable, addrMap, start, forward);
|
keyIter = new AddressKeyIterator(table, addrMap, start, forward);
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
errHandler.dbError(e);
|
errHandler.dbError(e);
|
||||||
|
@ -564,23 +598,36 @@ public abstract class PropertyMapDB<T> implements PropertyMap<T> {
|
||||||
/**
|
/**
|
||||||
* Invalidates the cache.
|
* Invalidates the cache.
|
||||||
*/
|
*/
|
||||||
public void invalidateCache() {
|
public void invalidate() {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
propertyTable = dbHandle.getTable(getTableName());
|
setInvalid();
|
||||||
cache = new ObjectCache(DEFAULT_CACHE_SIZE);
|
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
lock.release();
|
lock.release();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean refresh() {
|
||||||
|
cache = new ObjectCache<>(DEFAULT_CACHE_SIZE);
|
||||||
|
propertyTable = dbHandle.getTable(getTableName());
|
||||||
|
if (propertyTable != null) {
|
||||||
|
if (!propertyTable.getSchema().equals(schema)) {
|
||||||
|
propertyTable = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Must assume lazy table and empty map
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void moveRange(Address start, Address end, Address newStart) {
|
public void moveRange(Address start, Address end, Address newStart) {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
cache = new ObjectCache(DEFAULT_CACHE_SIZE);
|
checkDeleted();
|
||||||
|
cache = new ObjectCache<>(DEFAULT_CACHE_SIZE);
|
||||||
if (propertyTable != null) {
|
if (propertyTable != null) {
|
||||||
try {
|
try {
|
||||||
DatabaseTableUtils.updateAddressKey(propertyTable, addrMap, start, end,
|
DatabaseTableUtils.updateAddressKey(propertyTable, addrMap, start, end,
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package ghidra.program.database.properties;
|
package ghidra.program.database.properties;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import db.*;
|
import db.*;
|
||||||
import db.util.ErrorHandler;
|
import db.util.ErrorHandler;
|
||||||
|
@ -34,6 +35,24 @@ import ghidra.util.task.TaskMonitor;
|
||||||
*/
|
*/
|
||||||
public class StringPropertyMapDB extends PropertyMapDB<String> implements StringPropertyMap {
|
public class StringPropertyMapDB extends PropertyMapDB<String> implements StringPropertyMap {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single non-capturing lambda record reader function is used to avoid the possibility of
|
||||||
|
* multiple synthetic class instantiations.
|
||||||
|
*/
|
||||||
|
private Function<Long, String> valueReader = addrKey -> {
|
||||||
|
Table table = propertyTable;
|
||||||
|
DBRecord rec = null;
|
||||||
|
try {
|
||||||
|
if (table != null) {
|
||||||
|
rec = table.getRecord(addrKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
errHandler.dbError(e);
|
||||||
|
}
|
||||||
|
return rec != null ? rec.getString(PROPERTY_VALUE_COL) : null;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct an String property map.
|
* Construct an String property map.
|
||||||
* @param dbHandle database handle.
|
* @param dbHandle database handle.
|
||||||
|
@ -59,25 +78,24 @@ public class StringPropertyMapDB extends PropertyMapDB<String> implements String
|
||||||
public void add(Address addr, String value) {
|
public void add(Address addr, String value) {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
long key = addrMap.getKey(addr, true);
|
checkDeleted();
|
||||||
|
|
||||||
|
long addrKey = addrMap.getKey(addr, true);
|
||||||
|
|
||||||
String oldValue = null;
|
String oldValue = null;
|
||||||
if (propertyTable == null) {
|
if (propertyTable == null) {
|
||||||
createTable(StringField.INSTANCE);
|
createTable(StringField.INSTANCE);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
oldValue = (String) cache.get(key);
|
oldValue = cache.get(addrKey);
|
||||||
if (oldValue == null) {
|
if (oldValue == null) {
|
||||||
DBRecord rec = propertyTable.getRecord(key);
|
oldValue = valueReader.apply(addrKey);
|
||||||
if (rec != null) {
|
|
||||||
oldValue = rec.getString(PROPERTY_VALUE_COL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
DBRecord rec = schema.createRecord(addrKey);
|
||||||
DBRecord rec = schema.createRecord(key);
|
|
||||||
rec.setString(PROPERTY_VALUE_COL, value);
|
rec.setString(PROPERTY_VALUE_COL, value);
|
||||||
propertyTable.putRecord(rec);
|
propertyTable.putRecord(rec);
|
||||||
cache.put(key, value);
|
cache.put(addrKey, value);
|
||||||
changeMgr.setPropertyChanged(name, addr, oldValue, value);
|
changeMgr.setPropertyChanged(name, addr, oldValue, value);
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
|
@ -91,38 +109,16 @@ public class StringPropertyMapDB extends PropertyMapDB<String> implements String
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getString(Address addr) {
|
public String getString(Address addr) {
|
||||||
if (propertyTable == null) {
|
validate(lock);
|
||||||
|
Table table = propertyTable;
|
||||||
|
if (table == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
long addrKey = addrMap.getKey(addr, false);
|
||||||
String str = null;
|
if (addrKey == AddressMap.INVALID_ADDRESS_KEY) {
|
||||||
|
|
||||||
lock.acquire();
|
|
||||||
try {
|
|
||||||
long key = addrMap.getKey(addr, false);
|
|
||||||
if (key == AddressMap.INVALID_ADDRESS_KEY) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
str = (String) cache.get(key);
|
return cache.computeIfAbsent(addrKey, valueReader);
|
||||||
if (str != null) {
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
DBRecord rec = propertyTable.getRecord(key);
|
|
||||||
if (rec == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
str = rec.getString(PROPERTY_VALUE_COL);
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
errHandler.dbError(e);
|
|
||||||
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -37,7 +37,7 @@ import ghidra.util.task.TaskMonitor;
|
||||||
*/
|
*/
|
||||||
public class VoidPropertyMapDB extends PropertyMapDB<Boolean> implements VoidPropertyMap {
|
public class VoidPropertyMapDB extends PropertyMapDB<Boolean> implements VoidPropertyMap {
|
||||||
|
|
||||||
private static Object VOID_OBJECT = new Object();
|
private static Boolean TRUE = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct an void object property map.
|
* Construct an void object property map.
|
||||||
|
@ -64,15 +64,17 @@ public class VoidPropertyMapDB extends PropertyMapDB<Boolean> implements VoidPro
|
||||||
public void add(Address addr) {
|
public void add(Address addr) {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
long key = addrMap.getKey(addr, true);
|
checkDeleted();
|
||||||
|
|
||||||
|
long addrKey = addrMap.getKey(addr, true);
|
||||||
Boolean oldValue = hasProperty(addr);
|
Boolean oldValue = hasProperty(addr);
|
||||||
|
|
||||||
if (propertyTable == null) {
|
if (propertyTable == null) {
|
||||||
createTable(null);
|
createTable(null);
|
||||||
}
|
}
|
||||||
DBRecord rec = schema.createRecord(key);
|
DBRecord rec = schema.createRecord(addrKey);
|
||||||
propertyTable.putRecord(rec);
|
propertyTable.putRecord(rec);
|
||||||
cache.put(key, VOID_OBJECT);
|
cache.put(addrKey, TRUE);
|
||||||
changeMgr.setPropertyChanged(name, addr, oldValue, true);
|
changeMgr.setPropertyChanged(name, addr, oldValue, true);
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
|
|
|
@ -56,19 +56,11 @@ public class GenericAddress implements Address {
|
||||||
this.addrSpace = addrSpace;
|
this.addrSpace = addrSpace;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @see ghidra.program.model.address.Address#getAddress(java.lang.String)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Address getAddress(String addrString) throws AddressFormatException {
|
public Address getAddress(String addrString) throws AddressFormatException {
|
||||||
return addrSpace.getAddress(addrString);
|
return addrSpace.getAddress(addrString);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @see ghidra.program.model.address.Address#getNewAddress(long)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Address getNewAddress(long byteOffset) {
|
public Address getNewAddress(long byteOffset) {
|
||||||
return addrSpace.getAddress(byteOffset);
|
return addrSpace.getAddress(byteOffset);
|
||||||
|
@ -86,10 +78,6 @@ public class GenericAddress implements Address {
|
||||||
return addrSpace.getTruncatedAddress(addrOffset, isAddressableWordOffset);
|
return addrSpace.getTruncatedAddress(addrOffset, isAddressableWordOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @see ghidra.program.model.address.Address#getOffset()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public long getOffset() {
|
public long getOffset() {
|
||||||
return offset;
|
return offset;
|
||||||
|
@ -100,9 +88,6 @@ public class GenericAddress implements Address {
|
||||||
return addrSpace.getAddressableWordOffset(offset);
|
return addrSpace.getAddressableWordOffset(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.address.Address#getUnsignedOffset()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public long getUnsignedOffset() {
|
public long getUnsignedOffset() {
|
||||||
// TODO: Validity of offset within space is not verified
|
// TODO: Validity of offset within space is not verified
|
||||||
|
@ -117,37 +102,21 @@ public class GenericAddress implements Address {
|
||||||
return spaceSize + offset;
|
return spaceSize + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @see ghidra.program.model.address.Address#getAddressSpace()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public AddressSpace getAddressSpace() {
|
public AddressSpace getAddressSpace() {
|
||||||
return addrSpace;
|
return addrSpace;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @see ghidra.program.model.address.Address#getSize()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
return addrSpace.getSize();
|
return addrSpace.getSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @see ghidra.program.model.address.Address#subtract(ghidra.program.model.address.Address)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public long subtract(Address addr) {
|
public long subtract(Address addr) {
|
||||||
return addrSpace.subtract(this, addr);
|
return addrSpace.subtract(this, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @see ghidra.program.model.address.Address#subtractWrap(long)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Address subtractWrap(long displacement) {
|
public Address subtractWrap(long displacement) {
|
||||||
if (displacement == 0)
|
if (displacement == 0)
|
||||||
|
@ -155,9 +124,6 @@ public class GenericAddress implements Address {
|
||||||
return addrSpace.subtractWrap(this, displacement);
|
return addrSpace.subtractWrap(this, displacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.address.Address#subtractWrapSpace(long)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Address subtractWrapSpace(long displacement) {
|
public Address subtractWrapSpace(long displacement) {
|
||||||
if (displacement == 0)
|
if (displacement == 0)
|
||||||
|
@ -165,10 +131,6 @@ public class GenericAddress implements Address {
|
||||||
return addrSpace.subtractWrapSpace(this, displacement);
|
return addrSpace.subtractWrapSpace(this, displacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @see ghidra.program.model.address.Address#subtractNoWrap(long)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Address subtractNoWrap(long displacement) throws AddressOverflowException {
|
public Address subtractNoWrap(long displacement) throws AddressOverflowException {
|
||||||
if (displacement == 0)
|
if (displacement == 0)
|
||||||
|
@ -176,10 +138,6 @@ public class GenericAddress implements Address {
|
||||||
return addrSpace.subtractNoWrap(this, displacement);
|
return addrSpace.subtractNoWrap(this, displacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @see ghidra.program.model.address.Address#subtract(long)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Address subtract(long displacement) {
|
public Address subtract(long displacement) {
|
||||||
if (displacement == 0)
|
if (displacement == 0)
|
||||||
|
@ -187,9 +145,6 @@ public class GenericAddress implements Address {
|
||||||
return addrSpace.subtract(this, displacement);
|
return addrSpace.subtract(this, displacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.address.Address#addWrap(long)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Address addWrap(long displacement) {
|
public Address addWrap(long displacement) {
|
||||||
if (displacement == 0)
|
if (displacement == 0)
|
||||||
|
@ -197,9 +152,6 @@ public class GenericAddress implements Address {
|
||||||
return addrSpace.addWrap(this, displacement);
|
return addrSpace.addWrap(this, displacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.address.Address#addWrapSpace(long)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Address addWrapSpace(long displacement) {
|
public Address addWrapSpace(long displacement) {
|
||||||
if (displacement == 0)
|
if (displacement == 0)
|
||||||
|
@ -207,10 +159,6 @@ public class GenericAddress implements Address {
|
||||||
return addrSpace.addWrapSpace(this, displacement);
|
return addrSpace.addWrapSpace(this, displacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @see ghidra.program.model.address.Address#addNoWrap(long)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Address addNoWrap(long displacement) throws AddressOverflowException {
|
public Address addNoWrap(long displacement) throws AddressOverflowException {
|
||||||
if (displacement == 0)
|
if (displacement == 0)
|
||||||
|
@ -226,10 +174,6 @@ public class GenericAddress implements Address {
|
||||||
return addrSpace.addNoWrap(this, displacement);
|
return addrSpace.addNoWrap(this, displacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @see ghidra.program.model.address.Address#add(long)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Address add(long displacement) {
|
public Address add(long displacement) {
|
||||||
if (displacement == 0)
|
if (displacement == 0)
|
||||||
|
@ -237,10 +181,6 @@ public class GenericAddress implements Address {
|
||||||
return addrSpace.add(this, displacement);
|
return addrSpace.add(this, displacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @see ghidra.program.model.address.Address#isSuccessor(ghidra.program.model.address.Address)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSuccessor(Address addr) {
|
public boolean isSuccessor(Address addr) {
|
||||||
return addrSpace.isSuccessor(this, addr);
|
return addrSpace.isSuccessor(this, addr);
|
||||||
|
@ -259,26 +199,17 @@ public class GenericAddress implements Address {
|
||||||
return Long.compareUnsigned(offset, otherOffset);
|
return Long.compareUnsigned(offset, otherOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @see java.lang.Object#equals(java.lang.Object)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) {
|
if (this == o) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!(o instanceof GenericAddress)) {
|
if (!(o instanceof GenericAddress addr)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
GenericAddress addr = (GenericAddress) o;
|
return offset == addr.offset && addrSpace.equals(addr.getAddressSpace());
|
||||||
return addrSpace.equals(addr.getAddressSpace()) && offset == addr.offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @see java.lang.Object#hashCode()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int hash1 = addrSpace.hashCode();
|
int hash1 = addrSpace.hashCode();
|
||||||
|
@ -286,18 +217,11 @@ public class GenericAddress implements Address {
|
||||||
return (hash1 << 16) ^ hash3;
|
return (hash1 << 16) ^ hash3;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see java.lang.Object#toString()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return toString(addrSpace.showSpaceName(), MINIMUM_DIGITS);
|
return toString(addrSpace.showSpaceName(), MINIMUM_DIGITS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @see ghidra.program.model.address.Address#toString(java.lang.String)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public String toString(String prefix) {
|
public String toString(String prefix) {
|
||||||
boolean showSpace = prefix.length() == 0 && addrSpace.showSpaceName();
|
boolean showSpace = prefix.length() == 0 && addrSpace.showSpaceName();
|
||||||
|
@ -368,19 +292,11 @@ public class GenericAddress implements Address {
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @see ghidra.program.model.address.Address#hasSameAddressSpace(ghidra.program.model.address.Address)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasSameAddressSpace(Address addr) {
|
public boolean hasSameAddressSpace(Address addr) {
|
||||||
return addrSpace.equals(addr.getAddressSpace());
|
return addrSpace.equals(addr.getAddressSpace());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @see ghidra.program.model.address.Address#next()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Address next() {
|
public Address next() {
|
||||||
if (addrSpace.getMaxAddress().getOffset() == offset) {
|
if (addrSpace.getMaxAddress().getOffset() == offset) {
|
||||||
|
@ -389,9 +305,6 @@ public class GenericAddress implements Address {
|
||||||
return addrSpace.addWrap(this, 1);
|
return addrSpace.addWrap(this, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.address.Address#previous()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Address previous() {
|
public Address previous() {
|
||||||
if (addrSpace.getMinAddress().getOffset() == offset) {
|
if (addrSpace.getMinAddress().getOffset() == offset) {
|
||||||
|
@ -400,9 +313,6 @@ public class GenericAddress implements Address {
|
||||||
return addrSpace.subtractWrap(this, 1);
|
return addrSpace.subtractWrap(this, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.address.Address#getPhysicalAddress()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Address getPhysicalAddress() {
|
public Address getPhysicalAddress() {
|
||||||
AddressSpace physical = addrSpace.getPhysicalSpace();
|
AddressSpace physical = addrSpace.getPhysicalSpace();
|
||||||
|
@ -415,17 +325,11 @@ public class GenericAddress implements Address {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.address.Address#getPointerSize()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public int getPointerSize() {
|
public int getPointerSize() {
|
||||||
return addrSpace.getPointerSize();
|
return addrSpace.getPointerSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.address.Address#isMemoryAddress()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isMemoryAddress() {
|
public boolean isMemoryAddress() {
|
||||||
return addrSpace.isMemorySpace();
|
return addrSpace.isMemorySpace();
|
||||||
|
@ -441,57 +345,36 @@ public class GenericAddress implements Address {
|
||||||
return addrSpace.isNonLoadedMemorySpace();
|
return addrSpace.isNonLoadedMemorySpace();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.address.Address#isHashAddress()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isHashAddress() {
|
public boolean isHashAddress() {
|
||||||
return addrSpace.isHashSpace();
|
return addrSpace.isHashSpace();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.address.Address#isStackAddress()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isStackAddress() {
|
public boolean isStackAddress() {
|
||||||
return addrSpace.isStackSpace();
|
return addrSpace.isStackSpace();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.address.Address#isUniqueAddress()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isUniqueAddress() {
|
public boolean isUniqueAddress() {
|
||||||
return addrSpace.isUniqueSpace();
|
return addrSpace.isUniqueSpace();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.address.Address#isConstantAddress()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isConstantAddress() {
|
public boolean isConstantAddress() {
|
||||||
return addrSpace.isConstantSpace();
|
return addrSpace.isConstantSpace();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.address.Address#isVariableAddress()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isVariableAddress() {
|
public boolean isVariableAddress() {
|
||||||
return addrSpace.isVariableSpace();
|
return addrSpace.isVariableSpace();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.address.Address#isRegisterAddress()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isRegisterAddress() {
|
public boolean isRegisterAddress() {
|
||||||
return addrSpace.isRegisterSpace();
|
return addrSpace.isRegisterSpace();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.address.Address#isExternalAddress()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isExternalAddress() {
|
public boolean isExternalAddress() {
|
||||||
return addrSpace.isExternalSpace();
|
return addrSpace.isExternalSpace();
|
||||||
|
|
|
@ -141,7 +141,7 @@ public interface PropertyMapManager {
|
||||||
public boolean removePropertyMap(String propertyName);
|
public boolean removePropertyMap(String propertyName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an iterator over the names of all existing PropertyMaps.
|
* Returns an iterator over the names of all existing PropertyMaps sorted by name.
|
||||||
*/
|
*/
|
||||||
public Iterator<String> propertyManagers();
|
public Iterator<String> propertyManagers();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue