GP-1949 - MemoryMap, AddressMap and ELF MemorySectionResolver import

performance improvements
This commit is contained in:
ghidra1 2022-04-27 10:55:05 -04:00
parent 8e8b193ac1
commit db27e3cba0
6 changed files with 382 additions and 210 deletions

View file

@ -35,6 +35,7 @@ public abstract class MemorySectionResolver {
protected final Program program; protected final Program program;
private Set<String> usedBlockNames = new HashSet<>(); private Set<String> usedBlockNames = new HashSet<>();
private AddressSet physicalLoadedOverlaySet;
private List<MemorySection> sections = new ArrayList<>(); // built-up prior to resolve private List<MemorySection> sections = new ArrayList<>(); // built-up prior to resolve
private Map<String, Integer> sectionIndexMap = new HashMap<>(); private Map<String, Integer> sectionIndexMap = new HashMap<>();
@ -267,6 +268,16 @@ public abstract class MemorySectionResolver {
// build-up mapping of sections to a sequence of memory ranges // build-up mapping of sections to a sequence of memory ranges
sectionMemoryMap = new HashMap<>(); sectionMemoryMap = new HashMap<>();
physicalLoadedOverlaySet = new AddressSet();
for (MemoryBlock block : getMemory().getBlocks()) {
Address minAddr = block.getStart();
Address maxAddr = block.getEnd();
if (minAddr.isLoadedMemoryAddress() && minAddr.getAddressSpace().isOverlaySpace()) {
physicalLoadedOverlaySet.add(minAddr.getPhysicalAddress(),
maxAddr.getPhysicalAddress());
}
}
// process sections in reverse order - last-in takes precedence // process sections in reverse order - last-in takes precedence
int sectionCount = sections.size(); int sectionCount = sections.size();
monitor.initialize(sectionCount); monitor.initialize(sectionCount);
@ -390,6 +401,10 @@ public abstract class MemorySectionResolver {
minAddr = block.getStart(); minAddr = block.getStart();
maxAddr = block.getEnd(); maxAddr = block.getEnd();
usedBlockNames.add(blockName); usedBlockNames.add(blockName);
if (block.isOverlay() && minAddr.isLoadedMemoryAddress()) {
physicalLoadedOverlaySet.add(minAddr.getPhysicalAddress(),
maxAddr.getPhysicalAddress());
}
} }
else { else {
// block may be null due to unexpected conflict or pruning - allow to continue // block may be null due to unexpected conflict or pruning - allow to continue
@ -437,19 +452,10 @@ public abstract class MemorySectionResolver {
} }
// Get base memory conflict set // Get base memory conflict set
Memory memory = getMemory(); AddressSet conflictSet = getMemory().intersectRange(rangeMin, rangeMax);
AddressSet rangeSet = new AddressSet(rangeMin, rangeMax); if (!physicalLoadedOverlaySet.isEmpty()) {
AddressSet conflictSet = memory.intersect(rangeSet); // Add in loaded overlay physical address conflicts
conflictSet.add(physicalLoadedOverlaySet.intersectRange(rangeMin, rangeMax));
// Add in loaded overlay conflicts (use their physical address)
for (MemoryBlock block : memory.getBlocks()) {
Address minAddr = block.getStart();
Address maxAddr = block.getEnd();
if (minAddr.isLoadedMemoryAddress() && minAddr.getAddressSpace().isOverlaySpace()) {
AddressSet intersection = rangeSet.intersectRange(minAddr.getPhysicalAddress(),
maxAddr.getPhysicalAddress());
conflictSet.add(intersection);
}
} }
return conflictSet; return conflictSet;

View file

@ -99,6 +99,8 @@ public class AddressMapDB implements AddressMap {
private Address[] sortedBaseEndAddrs; private Address[] sortedBaseEndAddrs;
private List<KeyRange> allKeyRanges; // all existing key ranges (includes non-absolute memory, and external space) private List<KeyRange> allKeyRanges; // all existing key ranges (includes non-absolute memory, and external space)
private HashMap<Address, Integer> addrToIndexMap = new HashMap<Address, Integer>(); private HashMap<Address, Integer> addrToIndexMap = new HashMap<Address, Integer>();
private Address lastBaseAddress;
private int lastIndex;
private long baseImageOffset; // pertains to default address space only private long baseImageOffset; // pertains to default address space only
private List<AddressRange> segmentedRanges; // when using segmented memory, this list contains private List<AddressRange> segmentedRanges; // when using segmented memory, this list contains
@ -253,6 +255,7 @@ public class AddressMapDB implements AddressMap {
@Override @Override
public synchronized void invalidateCache() throws IOException { public synchronized void invalidateCache() throws IOException {
lastBaseAddress = null;
if (!readOnly) { if (!readOnly) {
baseAddrs = adapter.getBaseAddresses(true); baseAddrs = adapter.getBaseAddresses(true);
init(true); init(true);
@ -391,8 +394,13 @@ public class AddressMapDB implements AddressMap {
AddressSpace space = addr.getAddressSpace(); AddressSpace space = addr.getAddressSpace();
Address tBase = space.getAddressInThisSpaceOnly(normalizedBaseOffset); Address tBase = space.getAddressInThisSpaceOnly(normalizedBaseOffset);
if (tBase.equals(lastBaseAddress)) {
return lastIndex;
}
Integer tIndex = addrToIndexMap.get(tBase); Integer tIndex = addrToIndexMap.get(tBase);
if (tIndex != null) { if (tIndex != null) {
lastBaseAddress = tBase;
lastIndex = tIndex;
return tIndex; return tIndex;
} }
else if (indexOperation == INDEX_MATCH) { else if (indexOperation == INDEX_MATCH) {

View file

@ -107,6 +107,7 @@ public class MemoryBlockDB implements MemoryBlock {
* @return collection of blocks which map onto this block or null if none identified * @return collection of blocks which map onto this block or null if none identified
*/ */
Collection<MemoryBlockDB> getMappedBlocks() { Collection<MemoryBlockDB> getMappedBlocks() {
memMap.buildAddressSets(); // updates mappedBlocks if needed
return mappedBlocks; return mappedBlocks;
} }
@ -261,6 +262,7 @@ public class MemoryBlockDB implements MemoryBlock {
try { try {
checkValid(); checkValid();
setPermissionBit(EXECUTE, x); setPermissionBit(EXECUTE, x);
memMap.blockExecuteChanged(this);
memMap.fireBlockChanged(this); memMap.fireBlockChanged(this);
} }
finally { finally {
@ -276,6 +278,7 @@ public class MemoryBlockDB implements MemoryBlock {
setPermissionBit(READ, read); setPermissionBit(READ, read);
setPermissionBit(WRITE, write); setPermissionBit(WRITE, write);
setPermissionBit(EXECUTE, execute); setPermissionBit(EXECUTE, execute);
memMap.blockExecuteChanged(this);
memMap.fireBlockChanged(this); memMap.fireBlockChanged(this);
} }
finally { finally {

View file

@ -53,11 +53,21 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
private DataConverter defaultEndian; private DataConverter defaultEndian;
private List<MemoryBlockDB> blocks;// sorted list of blocks private List<MemoryBlockDB> blocks;// sorted list of blocks
private AddressSet addrSet = new AddressSet(); private AddressSet allAddrSet; // continuously updated
private AddressSet initializedLoadedAddrSet = new AddressSet();
private AddressSet allInitializedAddrSet = new AddressSet(); private MemoryAddressSetView addrSetView;
private AddressSetView executeSet = null;
private AddressSet externalBlockAddrSet; /**
* Address set views into program memory which are iterator safe
* for public API methods.
*/
private class MemoryAddressSetView {
private AddressSet all = new AddressSet();
private AddressSet initializedAndLoaded = new AddressSet();
private AddressSet initialized = new AddressSet();
private AddressSet externalBlock = new AddressSet();
private AddressSet execute = new AddressSet(); // may be replaced when block permissions change
}
private MemoryBlock lastBlock;// the last accessed block private MemoryBlock lastBlock;// the last accessed block
private LiveMemoryHandler liveMemory; private LiveMemoryHandler liveMemory;
@ -127,111 +137,83 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
} }
} }
private void buildAddressSets() { void buildAddressSets() {
addrSet = new AddressSet(); lock.acquire();
initializedLoadedAddrSet = new AddressSet(); try {
allInitializedAddrSet = new AddressSet(); // null addrSet signals address sets must be built otherwise return
externalBlockAddrSet = new AddressSet(); if (addrSetView != null) {
// we have to process the non-mapped blocks first because to process the mapped return;
// blocks we need the address sets for the non-mapped blocks to be complete }
for (MemoryBlockDB block : blocks) { addrSetView = new MemoryAddressSetView();
block.clearMappedBlockList();
if (!block.isMapped()) { // we have to process the non-mapped blocks first because to process the mapped
addBlockAddresses(block, false); // blocks we need the address sets for the non-mapped blocks to be complete
for (MemoryBlockDB block : blocks) {
block.clearMappedBlockList();
if (!block.isMapped()) {
addBlockAddresses(block);
}
}
// process all mapped blocks after non-mapped-blocks above
for (MemoryBlockDB block : blocks) {
if (block.isMapped()) {
addBlockAddresses(block);
}
}
if (allAddrSet == null) {
// An independent address set copy is maintained which may be changed
// dynamically when adding memory blocks. This is neccessary
// since such a changing address set may not be used to hand out
// iterators. Any time allAddrSet is modified addrSetView is
// set to null to signal it becoming stale.
allAddrSet = new AddressSet(addrSetView.all);
} }
} }
// process all mapped blocks after non-mapped-blocks above finally {
for (MemoryBlockDB block : blocks) { lock.release();
if (block.isMapped()) {
addBlockAddresses(block, false);
}
} }
} }
/** /**
* Update the <code>allInitializedAddrSet</code> and <code>initializedLoadedAddrSet</code> with * Update the <code>addrSetView.initialized</code> and <code>addrSetView.initializedAndLoaded</code> with
* relevant initialized addresses from the specified memory block. If block is not a * relevant initialized addresses from the specified memory block. If block is not a
* mapped-block and it may be a source to existing mapped-blocks then * mapped-block and it may be a source to existing mapped-blocks then
* <code>scanAllMappedBlocksIfNeeded</code> should be passed as <code>true</code> unless all * <code>scanAllMappedBlocksIfNeeded</code> should be passed as <code>true</code> unless all
* mapped blocks will be processed separately. * mapped blocks will be processed separately.
* *
* @param block memory block * @param block memory block
* @param scanAllMappedBlocksIfNeeded if true and block is initialized and not a mapped block * @param blockMayBeMappedOnto if true and block is initialized and not a mapped block
* all mapped blocks will be processed for possible introduction of newly initialized * all mapped blocks will be processed for possible introduction of newly initialized
* mapped regions. * mapped regions.
*/ */
private void addBlockAddresses(MemoryBlockDB block, boolean scanAllMappedBlocksIfNeeded) { private void addBlockAddresses(MemoryBlockDB block) {
AddressSet blockSet = new AddressSet(block.getStart(), block.getEnd()); Address start = block.getStart();
addrSet = addrSet.union(blockSet); Address end = block.getEnd();
addrSetView.all.add(start, end);
if (block.isExternalBlock()) { if (block.isExternalBlock()) {
// NOTE: no handling for mapped blocks which should never map onto EXTERNAL block addrSetView.externalBlock.add(start, end);
externalBlockAddrSet.add(block.getStart(), block.getEnd()); }
else if (block.isExecute()) {
addrSetView.execute.add(start, end);
} }
if (block.isMapped()) { if (block.isMapped()) {
// Identify source-blocks which block maps onto and add as a mapped-block to each of these // Identify source-blocks which block maps onto and add as a mapped-block to each of these
AddressRange mappedRange = block.getSourceInfos().get(0).getMappedRange().get(); AddressRange mappedRange = block.getSourceInfos().get(0).getMappedRange().get();
for (MemoryBlockDB b : getBlocks(mappedRange.getMinAddress(), for (MemoryBlockDB b : getBlocks(mappedRange.getMinAddress(),
mappedRange.getMaxAddress())) { mappedRange.getMaxAddress())) {
b.addMappedBlock(block); if (!b.isMapped()) {
b.addMappedBlock(block);
}
} }
AddressSet mappedSet = getMappedIntersection(block, addrSetView.initialized);
AddressSet mappedSet = getMappedIntersection(block, allInitializedAddrSet); addrSetView.initialized.add(mappedSet);
allInitializedAddrSet = allInitializedAddrSet.union(mappedSet); addrSetView.initializedAndLoaded.add(getMappedIntersection(block, addrSetView.initializedAndLoaded));
initializedLoadedAddrSet = initializedLoadedAddrSet.union(
getMappedIntersection(block, initializedLoadedAddrSet));
} }
else if (block.isInitialized()) { else if (block.isInitialized()) {
allInitializedAddrSet = allInitializedAddrSet.union(blockSet); addrSetView.initialized.add(block.getStart(), block.getEnd());
if (block.isLoaded()) { if (block.isLoaded()) {
initializedLoadedAddrSet = initializedLoadedAddrSet.union(blockSet); addrSetView.initializedAndLoaded.add(block.getStart(), block.getEnd());
}
if (scanAllMappedBlocksIfNeeded) {
// If only adding one initialized non-mapped-block we must scan all mapped-blocks
// which may utilize block as a byte source
for (MemoryBlockDB b : blocks) {
b.clearMappedBlockList();
}
for (MemoryBlockDB b : blocks) {
if (b.isMapped()) {
addBlockAddresses(b, false);
}
}
}
}
}
/**
* Update initialized address set for those mapped blocks which map onto the specified block
* which has just completed a transition of its' initialized state.
*
* @param block block whose initialized state has changed
* @param isInitialized true if block transitioned from uninitialized to initialized, else
* transition is from initialized to uninitialized.
*/
private void updateMappedAddresses(MemoryBlockDB block, boolean isInitialized) {
Collection<MemoryBlockDB> mappedBlocks = block.getMappedBlocks();
if (mappedBlocks == null) {
return;
}
AddressSet blockSet = new AddressSet(block.getStart(), block.getEnd());
boolean isLoaded = block.getStart().isLoadedMemoryAddress();
for (MemoryBlockDB mappedBlock : block.getMappedBlocks()) {
AddressSet mappedSet = getMappedIntersection(mappedBlock, blockSet);
if (isInitialized) {
allInitializedAddrSet = allInitializedAddrSet.union(mappedSet);
if (isLoaded) {
initializedLoadedAddrSet = initializedLoadedAddrSet.union(mappedSet);
}
}
else {
allInitializedAddrSet = allInitializedAddrSet.subtract(mappedSet);
if (isLoaded) {
initializedLoadedAddrSet = initializedLoadedAddrSet.union(mappedSet);
}
} }
} }
} }
@ -240,6 +222,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
synchronized (this) { synchronized (this) {
fileBytesAdapter.refresh(); fileBytesAdapter.refresh();
adapter.refreshMemory(); adapter.refreshMemory();
allAddrSet = null;
initializeBlocks(); initializeBlocks();
buildAddressSets(); buildAddressSets();
} }
@ -250,14 +233,29 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
} }
private synchronized void initializeBlocks() { private synchronized void initializeBlocks() {
List<MemoryBlockDB> newBlocks = adapter.getMemoryBlocks(); blocks = adapter.getMemoryBlocks();
lastBlock = null; lastBlock = null;
blocks = newBlocks;
nameBlockMap = new HashMap<>(); nameBlockMap = new HashMap<>();
executeSet = null; addrSetView = null; // signal stale view
addrMap.memoryMapChanged(this); addrMap.memoryMapChanged(this);
} }
void blockExecuteChanged(MemoryBlockDB block) {
// lock must be active
if (addrSetView == null) {
return;
}
// copy must be made to remain iterator safe
AddressSet set = new AddressSet(addrSetView.execute);
if (block.isExecute()) {
set.addRange(block.getStart(), block.getEnd());
}
else {
set.deleteRange(block.getStart(), block.getEnd());
}
addrSetView.execute = set;
}
public void setLanguage(Language newLanguage) { public void setLanguage(Language newLanguage) {
defaultEndian = newLanguage.isBigEndian() ? BIG_ENDIAN : LITTLE_ENDIAN; defaultEndian = newLanguage.isBigEndian() ? BIG_ENDIAN : LITTLE_ENDIAN;
} }
@ -316,17 +314,48 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
return getLoadedAndInitializedAddressSet(); return getLoadedAndInitializedAddressSet();
} }
private AddressSetView getIterableAddressSet() {
lock.acquire();
try {
if (addrSetView == null) {
buildAddressSets();
}
return new AddressSetViewAdapter(addrSetView.all);
}
finally {
lock.release();
}
}
@Override @Override
public AddressSetView getAllInitializedAddressSet() { public AddressSetView getAllInitializedAddressSet() {
return new AddressSetViewAdapter(allInitializedAddrSet); lock.acquire();
try {
if (addrSetView == null) {
buildAddressSets();
}
return new AddressSetViewAdapter(addrSetView.initialized);
}
finally {
lock.release();
}
} }
@Override @Override
public AddressSetView getLoadedAndInitializedAddressSet() { public AddressSetView getLoadedAndInitializedAddressSet() {
if (liveMemory != null) { if (liveMemory != null) {
return this;//all memory is initialized! return this; // all memory is initialized!
}
lock.acquire();
try {
if (addrSetView == null) {
buildAddressSets();
}
return new AddressSetViewAdapter(addrSetView.initializedAndLoaded);
}
finally {
lock.release();
} }
return new AddressSetViewAdapter(initializedLoadedAddrSet);
} }
void checkMemoryWrite(MemoryBlockDB block, Address start, long length) void checkMemoryWrite(MemoryBlockDB block, Address start, long length)
@ -514,9 +543,6 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
// name could have changed // name could have changed
nameBlockMap = new HashMap<>(); nameBlockMap = new HashMap<>();
// don't regenerate now, do lazily later if needed
executeSet = null;
} }
void fireBytesChanged(Address addr, int count) { void fireBytesChanged(Address addr, int count) {
@ -618,8 +644,8 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
try { try {
MemoryBlockDB newBlock = MemoryBlockDB newBlock =
adapter.createInitializedBlock(name, start, is, length, MemoryBlock.READ); adapter.createInitializedBlock(name, start, is, length, MemoryBlock.READ);
allAddrSet.add(newBlock.getStart(), newBlock.getEnd());
initializeBlocks(); initializeBlocks();
addBlockAddresses(newBlock, !overlay);
fireBlockAdded(newBlock); fireBlockAdded(newBlock);
return newBlock; return newBlock;
} }
@ -662,8 +688,8 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
try { try {
MemoryBlockDB newBlock = adapter.createFileBytesBlock(name, start, length, MemoryBlockDB newBlock = adapter.createFileBytesBlock(name, start, length,
fileBytes, offset, MemoryBlock.READ); fileBytes, offset, MemoryBlock.READ);
allAddrSet.add(newBlock.getStart(), newBlock.getEnd());
initializeBlocks(); initializeBlocks();
addBlockAddresses(newBlock, !overlay);
fireBlockAdded(newBlock); fireBlockAdded(newBlock);
return newBlock; return newBlock;
} }
@ -715,8 +741,8 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
try { try {
MemoryBlockDB newBlock = adapter.createBlock(MemoryBlockType.DEFAULT, name, start, MemoryBlockDB newBlock = adapter.createBlock(MemoryBlockType.DEFAULT, name, start,
size, null, false, MemoryBlock.READ, 0); size, null, false, MemoryBlock.READ, 0);
allAddrSet.add(newBlock.getStart(), newBlock.getEnd());
initializeBlocks(); initializeBlocks();
addBlockAddresses(newBlock, false);
fireBlockAdded(newBlock); fireBlockAdded(newBlock);
return newBlock; return newBlock;
} }
@ -750,8 +776,8 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
try { try {
MemoryBlockDB newBlock = adapter.createBlock(MemoryBlockType.BIT_MAPPED, name, MemoryBlockDB newBlock = adapter.createBlock(MemoryBlockType.BIT_MAPPED, name,
start, length, mappedAddress, false, MemoryBlock.READ, 0); start, length, mappedAddress, false, MemoryBlock.READ, 0);
allAddrSet.add(newBlock.getStart(), newBlock.getEnd());
initializeBlocks(); initializeBlocks();
addBlockAddresses(newBlock, false);
fireBlockAdded(newBlock); fireBlockAdded(newBlock);
return newBlock; return newBlock;
} }
@ -794,8 +820,8 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
try { try {
MemoryBlockDB newBlock = adapter.createBlock(MemoryBlockType.BYTE_MAPPED, name, MemoryBlockDB newBlock = adapter.createBlock(MemoryBlockType.BYTE_MAPPED, name,
start, length, mappedAddress, false, MemoryBlock.READ, mappingScheme); start, length, mappedAddress, false, MemoryBlock.READ, mappingScheme);
allAddrSet.add(newBlock.getStart(), newBlock.getEnd());
initializeBlocks(); initializeBlocks();
addBlockAddresses(newBlock, false);
fireBlockAdded(newBlock); fireBlockAdded(newBlock);
return newBlock; return newBlock;
} }
@ -842,8 +868,8 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
} }
MemoryBlockDB newBlock = adapter.createBlock(block.getType(), name, start, length, MemoryBlockDB newBlock = adapter.createBlock(block.getType(), name, start, length,
mappedAddr, block.isInitialized(), block.getPermissions(), mappingScheme); mappedAddr, block.isInitialized(), block.getPermissions(), mappingScheme);
allAddrSet.add(newBlock.getStart(), newBlock.getEnd());
initializeBlocks(); initializeBlocks();
addBlockAddresses(newBlock, !block.isMapped() && block.isInitialized());
fireBlockAdded(newBlock); fireBlockAdded(newBlock);
return newBlock; return newBlock;
} }
@ -860,7 +886,13 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
@Override @Override
public long getSize() { public long getSize() {
return addrSet.getNumAddresses(); lock.acquire();
try {
return allAddrSet.getNumAddresses();
}
finally {
lock.release();
}
} }
@Override @Override
@ -901,8 +933,8 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
// the code manager will be locked until the remove is done // the code manager will be locked until the remove is done
try { try {
Address newEndAddr = newStartAddr.addNoWrap(block.getSize() - 1); Address newEndAddr = newStartAddr.addNoWrap(block.getSize() - 1);
AddressSet set = new AddressSet(addrSet); AddressSet set = new AddressSet(allAddrSet); // could be slow
set.deleteRange(block.getStart(), block.getEnd()); set.delete(block.getStart(), block.getEnd());
if (set.intersects(newStartAddr, newEndAddr)) { if (set.intersects(newStartAddr, newEndAddr)) {
throw new MemoryConflictException( throw new MemoryConflictException(
"Block move conflicts with other existing memory block"); "Block move conflicts with other existing memory block");
@ -1006,7 +1038,6 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
reloadAll(); reloadAll();
newBlock = getBlockDB(block1Addr); newBlock = getBlockDB(block1Addr);
fireBlocksJoined(newBlock, block2Addr); fireBlocksJoined(newBlock, block2Addr);
} }
catch (IOException e) { catch (IOException e) {
program.dbError(e); program.dbError(e);
@ -1084,12 +1115,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
MemoryBlockDB memBlock = (MemoryBlockDB) unitializedBlock; MemoryBlockDB memBlock = (MemoryBlockDB) unitializedBlock;
try { try {
memBlock.initializeBlock(initialValue); memBlock.initializeBlock(initialValue);
allInitializedAddrSet.addRange(memBlock.getStart(), memBlock.getEnd()); initializeBlocks();
initializedLoadedAddrSet.addRange(memBlock.getStart(), memBlock.getEnd());
if (!memBlock.isMapped()) {
// update initialized sets for all blocks mapped to memBlock
updateMappedAddresses(memBlock, true);
}
fireBlockChanged(memBlock); fireBlockChanged(memBlock);
fireBytesChanged(memBlock.getStart(), (int) memBlock.getSize()); fireBytesChanged(memBlock.getStart(), (int) memBlock.getSize());
return memBlock; return memBlock;
@ -1125,12 +1151,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
try { try {
// FIXME: clear instructions in initializedBlock or any block which maps to it // FIXME: clear instructions in initializedBlock or any block which maps to it
memBlock.uninitializeBlock(); memBlock.uninitializeBlock();
allInitializedAddrSet.deleteRange(memBlock.getStart(), memBlock.getEnd()); initializeBlocks();
initializedLoadedAddrSet.deleteRange(memBlock.getStart(), memBlock.getEnd());
if (!memBlock.isMapped()) {
// update initialized sets for all blocks mapped to memBlock
updateMappedAddresses(memBlock, false);
}
fireBlockChanged(memBlock); fireBlockChanged(memBlock);
fireBytesChanged(memBlock.getStart(), (int) memBlock.getSize()); fireBytesChanged(memBlock.getStart(), (int) memBlock.getSize());
return memBlock; return memBlock;
@ -1153,8 +1174,8 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
if (monitor == null) { if (monitor == null) {
monitor = TaskMonitor.DUMMY; monitor = TaskMonitor.DUMMY;
} }
AddressSetView set = getLoadedAndInitializedAddressSet();
AddressIterator it = initializedLoadedAddrSet.getAddresses(addr, forward); AddressIterator it = set.getAddresses(addr, forward);
byte[] b = new byte[bytes.length]; byte[] b = new byte[bytes.length];
if (forward) { if (forward) {
while (it.hasNext() && !monitor.isCancelled()) { while (it.hasNext() && !monitor.isCancelled()) {
@ -1164,7 +1185,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
try { try {
Address jumpAddr = addr2.addNoWrap(-moffset); Address jumpAddr = addr2.addNoWrap(-moffset);
if (jumpAddr.hasSameAddressSpace(addr2)) { if (jumpAddr.hasSameAddressSpace(addr2)) {
it = initializedLoadedAddrSet.getAddresses(jumpAddr, forward); it = set.getAddresses(jumpAddr, forward);
} }
monitor.incrementProgress(-moffset); monitor.incrementProgress(-moffset);
} }
@ -1200,7 +1221,8 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
if (monitor == null) { if (monitor == null) {
monitor = TaskMonitor.DUMMY; monitor = TaskMonitor.DUMMY;
} }
AddressIterator it = allInitializedAddrSet.getAddresses(startAddr, forward); AddressSetView set = getLoadedAndInitializedAddressSet();
AddressIterator it = set.getAddresses(startAddr, forward);
byte[] b = new byte[bytes.length]; byte[] b = new byte[bytes.length];
if (forward) { if (forward) {
while (it.hasNext() && !monitor.isCancelled()) { while (it.hasNext() && !monitor.isCancelled()) {
@ -1213,7 +1235,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
try { try {
Address jumpAddr = addr2.addNoWrap(-moffset); Address jumpAddr = addr2.addNoWrap(-moffset);
if (jumpAddr.hasSameAddressSpace(addr2)) { if (jumpAddr.hasSameAddressSpace(addr2)) {
it = allInitializedAddrSet.getAddresses(jumpAddr, forward); it = set.getAddresses(jumpAddr, forward);
} }
monitor.incrementProgress(-moffset); monitor.incrementProgress(-moffset);
} }
@ -1753,47 +1775,98 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
@Override @Override
public boolean contains(Address addr) { public boolean contains(Address addr) {
return addrSet.contains(addr); lock.acquire();
try {
return allAddrSet.contains(addr);
}
finally {
lock.release();
}
} }
@Override @Override
public boolean contains(Address start, Address end) { public boolean contains(Address start, Address end) {
return addrSet.contains(start, end); lock.acquire();
try {
return allAddrSet.contains(start, end);
}
finally {
lock.release();
}
} }
@Override @Override
public boolean contains(AddressSetView set) { public boolean contains(AddressSetView s) {
return addrSet.contains(set); lock.acquire();
try {
return allAddrSet.contains(s);
}
finally {
lock.release();
}
} }
@Override @Override
public boolean isEmpty() { public boolean isEmpty() {
return addrSet.isEmpty(); lock.acquire();
try {
return allAddrSet.isEmpty();
}
finally {
lock.release();
}
} }
@Override @Override
public boolean isExternalBlockAddress(Address addr) { public boolean isExternalBlockAddress(Address addr) {
return externalBlockAddrSet.contains(addr); lock.acquire();
try {
if (addrSetView == null) {
buildAddressSets();
}
return addrSetView.externalBlock.contains(addr);
}
finally {
lock.release();
}
} }
@Override @Override
public Address getMinAddress() { public Address getMinAddress() {
return addrSet.getMinAddress(); lock.acquire();
try {
return allAddrSet.getMinAddress();
}
finally {
lock.release();
}
} }
@Override @Override
public Address getMaxAddress() { public Address getMaxAddress() {
return addrSet.getMaxAddress(); lock.acquire();
try {
return allAddrSet.getMaxAddress();
}
finally {
lock.release();
}
} }
@Override @Override
public int getNumAddressRanges() { public int getNumAddressRanges() {
return addrSet.getNumAddressRanges(); lock.acquire();
try {
return allAddrSet.getNumAddressRanges();
}
finally {
lock.release();
}
} }
@Override @Override
public AddressRangeIterator getAddressRanges() { public AddressRangeIterator getAddressRanges() {
return addrSet.getAddressRanges(); return getIterableAddressSet().getAddressRanges();
} }
@Override @Override
@ -1803,62 +1876,116 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
@Override @Override
public AddressRangeIterator getAddressRanges(boolean startAtFront) { public AddressRangeIterator getAddressRanges(boolean startAtFront) {
return addrSet.getAddressRanges(startAtFront); return getIterableAddressSet().getAddressRanges(startAtFront);
} }
@Override @Override
public long getNumAddresses() { public long getNumAddresses() {
return addrSet.getNumAddresses(); lock.acquire();
try {
return allAddrSet.getNumAddresses();
}
finally {
lock.release();
}
} }
@Override @Override
public AddressIterator getAddresses(boolean forward) { public AddressIterator getAddresses(boolean forward) {
return addrSet.getAddresses(forward); return getIterableAddressSet().getAddresses(forward);
} }
@Override @Override
public AddressIterator getAddresses(Address start, boolean forward) { public AddressIterator getAddresses(Address start, boolean forward) {
return addrSet.getAddresses(start, forward); return getIterableAddressSet().getAddresses(start, forward);
} }
@Override @Override
public boolean intersects(AddressSetView set) { public boolean intersects(AddressSetView set) {
return addrSet.intersects(set); lock.acquire();
try {
return allAddrSet.intersects(set);
}
finally {
lock.release();
}
} }
@Override @Override
public boolean intersects(Address start, Address end) { public boolean intersects(Address start, Address end) {
return addrSet.intersects(start, end); lock.acquire();
try {
return allAddrSet.intersects(start, end);
}
finally {
lock.release();
}
} }
@Override @Override
public AddressSet intersect(AddressSetView set) { public AddressSet intersect(AddressSetView set) {
return addrSet.intersect(set); lock.acquire();
try {
return allAddrSet.intersect(set);
}
finally {
lock.release();
}
} }
@Override @Override
public AddressSet intersectRange(Address start, Address end) { public AddressSet intersectRange(Address start, Address end) {
return addrSet.intersectRange(start, end); lock.acquire();
try {
return allAddrSet.intersectRange(start, end);
}
finally {
lock.release();
}
} }
@Override @Override
public AddressSet union(AddressSetView set) { public AddressSet union(AddressSetView set) {
return addrSet.union(set); lock.acquire();
try {
return allAddrSet.union(set);
}
finally {
lock.release();
}
} }
@Override @Override
public AddressSet subtract(AddressSetView set) { public AddressSet subtract(AddressSetView set) {
return addrSet.subtract(set); lock.acquire();
try {
return allAddrSet.subtract(set);
}
finally {
lock.release();
}
} }
@Override @Override
public AddressSet xor(AddressSetView set) { public AddressSet xor(AddressSetView set) {
return addrSet.xor(set); lock.acquire();
try {
return allAddrSet.xor(set);
}
finally {
lock.release();
}
} }
@Override @Override
public boolean hasSameAddresses(AddressSetView set) { public boolean hasSameAddresses(AddressSetView set) {
return addrSet.hasSameAddresses(set); lock.acquire();
try {
return allAddrSet.hasSameAddresses(set);
}
finally {
lock.release();
}
} }
@Override @Override
@ -1870,15 +1997,17 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
MemoryBlockDB memBlock = (MemoryBlockDB) block; MemoryBlockDB memBlock = (MemoryBlockDB) block;
Address startAddress = block.getStart(); Address startAddress = block.getStart();
Address endAddress = block.getEnd();
program.setEventsEnabled(false);// ensure that no domain object change program.setEventsEnabled(false);// ensure that no domain object change
// events go out that would cause screen updates; // events go out that would cause screen updates;
// the code manager will be locked until the remove is done // the code manager will be locked until the remove is done
try { try {
program.deleteAddressRange(startAddress, memBlock.getEnd(), monitor); program.deleteAddressRange(startAddress, endAddress, monitor);
memBlock.delete(); memBlock.delete();
reloadAll(); allAddrSet.delete(startAddress, endAddress);
initializeBlocks();
} }
catch (IOException e) { catch (IOException e) {
program.dbError(e); program.dbError(e);
@ -1943,7 +2072,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
"Block may not span image base address (" + imageBase + ")"); "Block may not span image base address (" + imageBase + ")");
} }
} }
if (addrSet.intersects(start, end)) { if (allAddrSet.intersects(start, end)) {
throw new MemoryConflictException( throw new MemoryConflictException(
"Part of range (" + start + ", " + end + ") already exists in memory."); "Part of range (" + start + ", " + end + ") already exists in memory.");
} }
@ -2062,19 +2191,25 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj instanceof Memory) { lock.acquire();
return obj == this; try {
} if (obj instanceof Memory) {
if (obj instanceof AddressSetView) { return obj == this;
lock.acquire();
try {
return addrSet.equals(obj);
} }
finally { if (obj instanceof AddressSetView) {
lock.release(); lock.acquire();
try {
return allAddrSet.equals(obj);
}
finally {
lock.release();
}
} }
return false;
}
finally {
lock.release();
} }
return false;
} }
@Override @Override
@ -2084,28 +2219,12 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
@Override @Override
public AddressSetView getExecuteSet() { public AddressSetView getExecuteSet() {
AddressSetView set = executeSet;
if (set == null) {
set = computeExecuteSet();
}
return set;
}
/**
* @return executable address set
*/
private AddressSetView computeExecuteSet() {
lock.acquire(); lock.acquire();
try { try {
AddressSet set = new AddressSet(); if (addrSetView == null) {
for (MemoryBlock block : blocks) { buildAddressSets();
if (block.isExecute()) {
set.addRange(block.getStart(), block.getEnd());
}
} }
executeSet = new AddressSetViewAdapter(set); return new AddressSetViewAdapter(addrSetView.execute);
return executeSet;
} }
finally { finally {
lock.release(); lock.release();
@ -2119,37 +2238,61 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
@Override @Override
public AddressRangeIterator getAddressRanges(Address start, boolean forward) { public AddressRangeIterator getAddressRanges(Address start, boolean forward) {
return addrSet.getAddressRanges(start, forward); return getIterableAddressSet().getAddressRanges(start, forward);
} }
@Override @Override
public AddressRange getFirstRange() { public AddressRange getFirstRange() {
return addrSet.getFirstRange(); lock.acquire();
try {
return allAddrSet.getFirstRange();
}
finally {
lock.release();
}
} }
@Override @Override
public AddressRange getLastRange() { public AddressRange getLastRange() {
return addrSet.getLastRange(); lock.acquire();
try {
return allAddrSet.getLastRange();
}
finally {
lock.release();
}
} }
@Override @Override
public AddressRange getRangeContaining(Address address) { public AddressRange getRangeContaining(Address address) {
return addrSet.getRangeContaining(address); lock.acquire();
try {
return allAddrSet.getRangeContaining(address);
}
finally {
lock.release();
}
} }
@Override @Override
public Iterator<AddressRange> iterator(boolean forward) { public Iterator<AddressRange> iterator(boolean forward) {
return addrSet.iterator(forward); return getIterableAddressSet().iterator(forward);
} }
@Override @Override
public Iterator<AddressRange> iterator(Address start, boolean forward) { public Iterator<AddressRange> iterator(Address start, boolean forward) {
return addrSet.iterator(start, forward); return getIterableAddressSet().iterator(start, forward);
} }
@Override @Override
public Address findFirstAddressInCommon(AddressSetView set) { public Address findFirstAddressInCommon(AddressSetView set) {
return addrSet.findFirstAddressInCommon(set); lock.acquire();
try {
return allAddrSet.findFirstAddressInCommon(set);
}
finally {
lock.release();
}
} }
@Override @Override
@ -2180,10 +2323,17 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
@Override @Override
public FileBytes createFileBytes(String filename, long offset, long size, InputStream is, public FileBytes createFileBytes(String filename, long offset, long size, InputStream is,
TaskMonitor monitor) throws IOException, CancelledException { TaskMonitor monitor) throws IOException, CancelledException {
long oldProgressMax = 0;
long oldProgress = 0;
if (monitor != null) {
oldProgressMax = monitor.getMaximum();
oldProgress = monitor.getProgress();
}
lock.acquire(); lock.acquire();
try { try {
if (monitor != null && is != null) { if (monitor != null && is != null) {
is = new MonitoredInputStream(is, monitor); is = new MonitoredInputStream(is, monitor);
monitor.initialize(size);
} }
return fileBytesAdapter.createFileBytes(filename, offset, size, is); return fileBytesAdapter.createFileBytes(filename, offset, size, is);
} }
@ -2192,6 +2342,10 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
} }
finally { finally {
lock.release(); lock.release();
if (monitor != null) {
monitor.setMaximum(oldProgressMax);
monitor.setProgress(oldProgress);
}
} }
} }

View file

@ -76,7 +76,7 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter {
private MemoryMapDB memMap; private MemoryMapDB memMap;
private AddressMapDB addrMap; private AddressMapDB addrMap;
private List<MemoryBlockDB> memoryBlocks = new ArrayList<>(); private List<MemoryBlockDB> memoryBlocks = new ArrayList<>(); // sorted list of blocks
private long maxSubBlockSize; private long maxSubBlockSize;
public MemoryMapDBAdapterV3(DBHandle handle, MemoryMapDB memMap, long maxSubBlockSize, public MemoryMapDBAdapterV3(DBHandle handle, MemoryMapDB memMap, long maxSubBlockSize,
@ -145,6 +145,14 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter {
return memoryBlocks; return memoryBlocks;
} }
private void cacheNewBlock(MemoryBlockDB newBlock) {
int insertionIndex = Collections.binarySearch(memoryBlocks, newBlock);
if (insertionIndex >= 0) { // should not find direct hit
throw new AssertException("New memory block collides with existing block");
}
memoryBlocks.add(-insertionIndex - 1, newBlock);
}
@Override @Override
MemoryBlockDB createInitializedBlock(String name, Address startAddr, InputStream is, MemoryBlockDB createInitializedBlock(String name, Address startAddr, InputStream is,
long length, int permissions) throws AddressOverflowException, IOException { long length, int permissions) throws AddressOverflowException, IOException {
@ -169,8 +177,7 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter {
memBlockTable.putRecord(blockRecord); memBlockTable.putRecord(blockRecord);
MemoryBlockDB newBlock = new MemoryBlockDB(this, blockRecord, subBlocks); MemoryBlockDB newBlock = new MemoryBlockDB(this, blockRecord, subBlocks);
memoryBlocks.add(newBlock); cacheNewBlock(newBlock);
Collections.sort(memoryBlocks);
return newBlock; return newBlock;
} }
catch (IOCancelledException e) { catch (IOCancelledException e) {
@ -219,8 +226,7 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter {
memBlockTable.putRecord(blockRecord); memBlockTable.putRecord(blockRecord);
MemoryBlockDB newBlock = new MemoryBlockDB(this, blockRecord, subBlocks); MemoryBlockDB newBlock = new MemoryBlockDB(this, blockRecord, subBlocks);
memoryBlocks.add(newBlock); cacheNewBlock(newBlock);
Collections.sort(memoryBlocks);
return newBlock; return newBlock;
} }
@ -237,8 +243,7 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter {
memBlockTable.putRecord(blockRecord); memBlockTable.putRecord(blockRecord);
MemoryBlockDB newBlock = new MemoryBlockDB(this, blockRecord, subBlocks); MemoryBlockDB newBlock = new MemoryBlockDB(this, blockRecord, subBlocks);
memoryBlocks.add(newBlock); cacheNewBlock(newBlock);
Collections.sort(memoryBlocks);
return newBlock; return newBlock;
} }
@ -256,11 +261,7 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter {
memBlockTable.putRecord(blockRecord); memBlockTable.putRecord(blockRecord);
MemoryBlockDB newBlock = new MemoryBlockDB(this, blockRecord, splitBlocks); MemoryBlockDB newBlock = new MemoryBlockDB(this, blockRecord, splitBlocks);
int insertionIndex = Collections.binarySearch(memoryBlocks, newBlock); cacheNewBlock(newBlock);
if (insertionIndex >= 0) { // should not find direct hit
throw new AssertException("New memory block collides with existing block");
}
memoryBlocks.add(-insertionIndex - 1, newBlock);
return newBlock; return newBlock;
} }
@ -293,8 +294,7 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter {
memBlockTable.putRecord(blockRecord); memBlockTable.putRecord(blockRecord);
MemoryBlockDB newBlock = new MemoryBlockDB(this, blockRecord, subBlocks); MemoryBlockDB newBlock = new MemoryBlockDB(this, blockRecord, subBlocks);
memoryBlocks.add(newBlock); cacheNewBlock(newBlock);
Collections.sort(memoryBlocks);
return newBlock; return newBlock;
} }
@ -314,8 +314,7 @@ public class MemoryMapDBAdapterV3 extends MemoryMapDBAdapter {
memBlockTable.putRecord(blockRecord); memBlockTable.putRecord(blockRecord);
MemoryBlockDB newBlock = new MemoryBlockDB(this, blockRecord, subBlocks); MemoryBlockDB newBlock = new MemoryBlockDB(this, blockRecord, subBlocks);
memoryBlocks.add(newBlock); cacheNewBlock(newBlock);
Collections.sort(memoryBlocks);
return newBlock; return newBlock;
} }

View file

@ -414,6 +414,7 @@ public interface Memory extends AddressSetView {
/** /**
* Finds a sequence of contiguous bytes that match the * Finds a sequence of contiguous bytes that match the
* given byte array at all bit positions where the mask contains an "on" bit. * given byte array at all bit positions where the mask contains an "on" bit.
* Search is performed over loaded memory only.
* *
* @param addr The beginning address in memory to search. * @param addr The beginning address in memory to search.
* @param bytes the array of bytes to search for. * @param bytes the array of bytes to search for.
@ -432,6 +433,7 @@ public interface Memory extends AddressSetView {
* Finds a sequence of contiguous bytes that match the * Finds a sequence of contiguous bytes that match the
* given byte array at all bit positions where the mask contains an "on" bit. * given byte array at all bit positions where the mask contains an "on" bit.
* Starts at startAddr and ends at endAddr. * Starts at startAddr and ends at endAddr.
* Search is performed over loaded memory only.
* If forward is true, search starts at startAddr and will end if startAddr "&gt;" endAddr. * If forward is true, search starts at startAddr and will end if startAddr "&gt;" endAddr.
* If forward is false, search starts at start addr and will end if startAddr "&lt;" endAddr. * If forward is false, search starts at start addr and will end if startAddr "&lt;" endAddr.
* *