diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTrace.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTrace.java index 8c64fe3141..3e4c80d1d2 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTrace.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTrace.java @@ -27,11 +27,12 @@ import generic.depends.DependentService; import generic.depends.err.ServiceConstructionException; import ghidra.framework.options.Options; import ghidra.lifecycle.Internal; -import ghidra.program.database.ProgramAddressFactory; import ghidra.program.model.address.*; import ghidra.program.model.data.*; import ghidra.program.model.lang.*; import ghidra.program.util.DefaultLanguageService; +import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter; +import ghidra.trace.database.address.TraceAddressFactory; import ghidra.trace.database.bookmark.DBTraceBookmarkManager; import ghidra.trace.database.breakpoint.DBTraceBreakpointManager; import ghidra.trace.database.context.DBTraceRegisterContextManager; @@ -103,6 +104,8 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace @DependentService protected DBTraceModuleManager moduleManager; @DependentService + protected DBTraceOverlaySpaceAdapter overlaySpaceAdapter; + @DependentService protected DBTraceReferenceManager referenceManager; @DependentService protected DBTraceRegisterContextManager registerContextManager; @@ -121,7 +124,7 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace protected Language baseLanguage; protected CompilerSpec baseCompilerSpec; - protected AddressFactory baseAddressFactory; + protected TraceAddressFactory baseAddressFactory; protected DBTraceChangeSet traceChangeSet; protected boolean recordChanges = false; @@ -142,7 +145,7 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace this.baseCompilerSpec = baseLanguage.getCompilerSpecByID(baseCompilerSpec.getCompilerSpecID()); this.baseAddressFactory = - new ProgramAddressFactory(this.baseLanguage, this.baseCompilerSpec); + new TraceAddressFactory(this.baseLanguage, this.baseCompilerSpec); try (UndoableTransaction tid = UndoableTransaction.start(this, "Create", false)) { initOptions(DBOpenMode.CREATE); @@ -197,7 +200,7 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace new LanguageID(traceInfo.getString(BASE_LANGUAGE, null))); baseCompilerSpec = baseLanguage.getCompilerSpecByID( new CompilerSpecID(traceInfo.getString(BASE_COMPILER, null))); - baseAddressFactory = new ProgramAddressFactory(baseLanguage, baseCompilerSpec); + baseAddressFactory = new TraceAddressFactory(baseLanguage, baseCompilerSpec); } } @@ -218,9 +221,10 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace if (as == AddressSpace.OTHER_SPACE) { return; } - if (baseLanguage.getAddressFactory().getAddressSpace(as.getSpaceID()) != as) { + if (baseAddressFactory.getAddressSpace(as.getSpaceID()) != as) { throw new IllegalArgumentException( - "AddressSpace '" + as + "' is not in this language: " + getBaseLanguage()); + "AddressSpace '" + as + "' is not in this trace (language=" + getBaseLanguage() + + ")"); } } @@ -247,7 +251,6 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace } @DependentService - @SuppressWarnings("hiding") protected DBTraceAddressPropertyManager createAddressPropertyManager( DBTraceThreadManager threadManager) throws CancelledException, IOException { return createTraceManager("Address Property Manager", @@ -256,7 +259,6 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace } @DependentService - @SuppressWarnings("hiding") protected DBTraceBookmarkManager createBookmarkManager(DBTraceThreadManager threadManager) throws CancelledException, IOException { return createTraceManager("Bookmark Manager", @@ -265,7 +267,6 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace } @DependentService - @SuppressWarnings("hiding") protected DBTraceBreakpointManager createBreakpointManager(DBTraceThreadManager threadManager) throws CancelledException, IOException { return createTraceManager("Breakpoint Manager", @@ -274,18 +275,17 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace } @DependentService - @SuppressWarnings("hiding") protected DBTraceCodeManager createCodeManager(DBTraceThreadManager threadManager, DBTraceLanguageManager languageManager, DBTraceDataTypeManager dataTypeManager, - DBTraceReferenceManager referenceManager) throws CancelledException, IOException { + DBTraceOverlaySpaceAdapter overlayAdapter, DBTraceReferenceManager referenceManager) + throws CancelledException, IOException { return createTraceManager("Code Manager", (openMode, monitor) -> new DBTraceCodeManager(dbh, openMode, rwLock, monitor, - baseLanguage, this, threadManager, languageManager, dataTypeManager, + baseLanguage, this, threadManager, languageManager, dataTypeManager, overlayAdapter, referenceManager)); } @DependentService - @SuppressWarnings("hiding") protected DBTraceCommentAdapter createCommentAdapter(DBTraceThreadManager threadManager) throws CancelledException, IOException { return createTraceManager("Comment Adapter", @@ -294,7 +294,6 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace } @DependentService - @SuppressWarnings("hiding") protected DBTraceDataSettingsAdapter createDataSettingsAdapter( DBTraceThreadManager threadManager) throws CancelledException, IOException { return createTraceManager("Data Settings Adapter", @@ -311,8 +310,7 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace } @DependentService - protected DBTraceEquateManager createEquateManager( - @SuppressWarnings("hiding") DBTraceThreadManager threadManager) + protected DBTraceEquateManager createEquateManager(DBTraceThreadManager threadManager) throws CancelledException, IOException { return createTraceManager("Equate Manager", (openMode, monitor) -> new DBTraceEquateManager(dbh, openMode, rwLock, monitor, @@ -328,12 +326,11 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace } @DependentService - @SuppressWarnings("hiding") - protected DBTraceMemoryManager createMemoryManager(DBTraceThreadManager threadManager) - throws IOException, CancelledException { + protected DBTraceMemoryManager createMemoryManager(DBTraceThreadManager threadManager, + DBTraceOverlaySpaceAdapter overlayAdapter) throws IOException, CancelledException { return createTraceManager("Memory Manager", (openMode, monitor) -> new DBTraceMemoryManager(dbh, openMode, rwLock, monitor, - baseLanguage, this, threadManager)); + baseLanguage, this, threadManager, overlayAdapter)); } @DependentService @@ -344,16 +341,22 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace } @DependentService - @SuppressWarnings("hiding") - protected DBTraceReferenceManager createReferenceManager(DBTraceThreadManager threadManager) + protected DBTraceOverlaySpaceAdapter createOverlaySpaceAdapter() throws CancelledException, IOException { - return createTraceManager("Reference Manager", - (openMode, monitor) -> new DBTraceReferenceManager(dbh, openMode, rwLock, monitor, - baseLanguage, this, threadManager)); + return createTraceManager("Overlay Space Adapter", + (openMode, monitor) -> new DBTraceOverlaySpaceAdapter(dbh, openMode, rwLock, monitor, + this)); + } + + @DependentService + protected DBTraceReferenceManager createReferenceManager(DBTraceThreadManager threadManager, + DBTraceOverlaySpaceAdapter overlayAdapter) throws CancelledException, IOException { + return createTraceManager("Reference Manager", + (openMode, monitor) -> new DBTraceReferenceManager(dbh, openMode, rwLock, monitor, + baseLanguage, this, threadManager, overlayAdapter)); } @DependentService - @SuppressWarnings("hiding") protected DBTraceRegisterContextManager createRegisterContextManager( DBTraceThreadManager threadManager, DBTraceLanguageManager languageManager) throws CancelledException, IOException { @@ -363,28 +366,28 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace } @DependentService - @SuppressWarnings("hiding") - protected DBTraceStackManager createStackManager(DBTraceThreadManager threadManager) - throws CancelledException, IOException { + protected DBTraceStackManager createStackManager(DBTraceThreadManager threadManager, + DBTraceOverlaySpaceAdapter overlayAdapter) throws CancelledException, IOException { return createTraceManager("Stack Manager", (openMode, monitor) -> new DBTraceStackManager(dbh, openMode, rwLock, monitor, this, - threadManager)); + threadManager, overlayAdapter)); } @DependentService - protected DBTraceStaticMappingManager createStaticMappingManager() - throws CancelledException, IOException { + protected DBTraceStaticMappingManager createStaticMappingManager( + DBTraceOverlaySpaceAdapter overlayAdapter) throws CancelledException, IOException { return createTraceManager("Static Mapping Manager", (openMode, - monitor) -> new DBTraceStaticMappingManager(dbh, openMode, rwLock, monitor, this)); + monitor) -> new DBTraceStaticMappingManager(dbh, openMode, rwLock, monitor, this, + overlayAdapter)); } @DependentService - @SuppressWarnings("hiding") protected DBTraceSymbolManager createSymbolManager(DBTraceThreadManager threadManager, - DBTraceDataTypeManager dataTypeManager) throws CancelledException, IOException { + DBTraceDataTypeManager dataTypeManager, DBTraceOverlaySpaceAdapter overlayAdapter) + throws CancelledException, IOException { return createTraceManager("Symbol Manager", (openMode, monitor) -> new DBTraceSymbolManager(dbh, openMode, rwLock, monitor, - baseLanguage, this, threadManager, dataTypeManager)); + baseLanguage, this, threadManager, dataTypeManager, overlayAdapter)); } @DependentService @@ -394,7 +397,6 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace } @DependentService - @SuppressWarnings("hiding") protected DBTraceTimeManager createTimeManager(DBTraceThreadManager threadManager) throws IOException, CancelledException { return createTraceManager("Time Manager", @@ -432,7 +434,12 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace return baseAddressFactory; } - // Internal + @Internal + public TraceAddressFactory getInternalAddressFactory() { + return baseAddressFactory; + } + + @Internal public DBTraceAddressPropertyManager getAddressPropertyManager() { return addressPropertyManager; } @@ -452,12 +459,12 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace return codeManager; } - // Internal + @Internal public DBTraceCommentAdapter getCommentAdapter() { return commentAdapter; } - // Internal + @Internal public DBTraceDataSettingsAdapter getDataSettingsAdapter() { return dataSettingsAdapter; } @@ -487,6 +494,11 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace return moduleManager; } + @Internal + public DBTraceOverlaySpaceAdapter getOverlaySpaceAdapter() { + return overlaySpaceAdapter; + } + @Override public DBTraceReferenceManager getReferenceManager() { return referenceManager; diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTraceUtils.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTraceUtils.java index d04cf6a40f..b26963eaaa 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTraceUtils.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTraceUtils.java @@ -19,6 +19,7 @@ import java.lang.reflect.Field; import java.net.MalformedURLException; import java.net.URL; import java.nio.ByteBuffer; +import java.nio.charset.Charset; import java.util.Iterator; import java.util.Objects; import java.util.function.BiConsumer; @@ -38,9 +39,6 @@ import ghidra.util.database.DBCachedObjectStoreFactory.AbstractDBFieldCodec; public enum DBTraceUtils { ; - public interface DecodesAddresses { - Address decodeAddress(int space, long offset); - } public static class OffsetSnap { public final long offset; @@ -123,52 +121,6 @@ public enum DBTraceUtils { } } - public static class AddressDBFieldCodec - extends AbstractDBFieldCodec { - - public AddressDBFieldCodec(Class objectType, Field field, int column) { - super(Address.class, objectType, BinaryField.class, field, column); - } - - protected byte[] encode(Address address) { - if (address == null) { - return null; - } - ByteBuffer buf = ByteBuffer.allocate(10); - short space = (short) address.getAddressSpace().getSpaceID(); - buf.putShort(space); - long offset = address.getOffset(); - buf.putLong(offset); - return buf.array(); - } - - @Override - public void store(Address value, BinaryField f) { - f.setBinaryData(encode(value)); - } - - @Override - protected void doStore(OT obj, DBRecord record) - throws IllegalArgumentException, IllegalAccessException { - record.setBinaryData(column, encode(getValue(obj))); - } - - @Override - protected void doLoad(OT obj, DBRecord record) - throws IllegalArgumentException, IllegalAccessException { - byte[] data = record.getBinaryData(column); - if (data == null) { - setValue(obj, null); - } - else { - ByteBuffer buf = ByteBuffer.wrap(data); - short space = buf.getShort(); - long offset = buf.getLong(); - setValue(obj, obj.decodeAddress(space, offset)); - } - } - } - public static class LanguageIDDBFieldCodec extends AbstractDBFieldCodec { diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/address/DBTraceOverlaySpaceAdapter.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/address/DBTraceOverlaySpaceAdapter.java new file mode 100644 index 0000000000..5c5d49ab99 --- /dev/null +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/address/DBTraceOverlaySpaceAdapter.java @@ -0,0 +1,274 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.trace.database.address; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.util.*; +import java.util.concurrent.locks.ReadWriteLock; + +import db.*; +import ghidra.program.model.address.*; +import ghidra.trace.database.DBTrace; +import ghidra.trace.database.DBTraceManager; +import ghidra.util.LockHold; +import ghidra.util.database.*; +import ghidra.util.database.DBCachedObjectStoreFactory.AbstractDBFieldCodec; +import ghidra.util.database.annot.*; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.exception.VersionException; +import ghidra.util.task.TaskMonitor; + +public class DBTraceOverlaySpaceAdapter implements DBTraceManager { + + /** + * An interface required for any object having a field using {@link AddressDBFieldCodec}. + */ + public interface DecodesAddresses { + /** + * Get the space adapter for the trace containing the object + * + * @return the adapter + */ + DBTraceOverlaySpaceAdapter getOverlaySpaceAdapter(); + } + + /** + * Used for objects having an {@link Address} field. + * + *

+ * Most managers storing things by address will actually have a table per space, so the address + * is encoded only as an offset. However, any other {@link Address} field (not constrained to + * the same space) will need to encode the space information as well. This codec can do that. + * The object will need to return its trace's space adapter, though. + * + * @param the type of object containing the field + */ + public static class AddressDBFieldCodec + extends AbstractDBFieldCodec { + static final Charset UTF8 = Charset.forName("UTF-8"); + + public AddressDBFieldCodec(Class objectType, Field field, int column) { + super(Address.class, objectType, BinaryField.class, field, column); + } + + protected byte[] encode(Address address) { + if (address == null) { + return null; + } + AddressSpace as = address.getAddressSpace(); + ByteBuffer buf = ByteBuffer.allocate(Byte.BYTES + Short.BYTES + Long.BYTES); + if (as instanceof OverlayAddressSpace) { + buf.put((byte) 1); + OverlayAddressSpace os = (OverlayAddressSpace) as; + buf.putShort((short) os.getDatabaseKey()); + } + else { + buf.put((byte) 0); + buf.putShort((short) as.getSpaceID()); + } + buf.putLong(address.getOffset()); + return buf.array(); + } + + @Override + public void store(Address value, BinaryField f) { + f.setBinaryData(encode(value)); + } + + @Override + protected void doStore(OT obj, DBRecord record) + throws IllegalArgumentException, IllegalAccessException { + record.setBinaryData(column, encode(getValue(obj))); + } + + @Override + protected void doLoad(OT obj, DBRecord record) + throws IllegalArgumentException, IllegalAccessException { + byte[] data = record.getBinaryData(column); + if (data == null) { + setValue(obj, null); + } + else { + ByteBuffer buf = ByteBuffer.wrap(data); + byte overlay = buf.get(); + final AddressSpace as; + if (overlay == 1) { + short key = buf.getShort(); + as = obj.getOverlaySpaceAdapter().spacesByKey.get(key & 0xffffL); + } + else { + short id = buf.getShort(); + as = obj.getOverlaySpaceAdapter().trace.getInternalAddressFactory() + .getAddressSpace(id); + } + long offset = buf.getLong(); + setValue(obj, as.getAddress(offset)); + } + } + } + + @DBAnnotatedObjectInfo(version = 0) + protected static class DBTraceOverlaySpaceEntry extends DBAnnotatedObject { + + static final String TABLE_NAME = "AddressSpaces"; + + static final String NAME_COLUMN_NAME = "Name"; + static final String BASE_COLUMN_NAME = "Base"; + + // NOTE: I don't care to record min/max limit + + @DBAnnotatedColumn(NAME_COLUMN_NAME) + static DBObjectColumn NAME_COLUMN; + @DBAnnotatedColumn(BASE_COLUMN_NAME) + static DBObjectColumn BASE_COLUMN; + + @DBAnnotatedField(column = NAME_COLUMN_NAME, indexed = true) + String name; + @DBAnnotatedField(column = BASE_COLUMN_NAME) + String baseSpace; + + public DBTraceOverlaySpaceEntry(DBCachedObjectStore store, DBRecord record) { + super(store, record); + } + + void set(String name, String baseSpace) { + this.name = name; + this.baseSpace = baseSpace; + update(NAME_COLUMN, BASE_COLUMN); + } + } + + protected final DBHandle dbh; + protected final ReadWriteLock lock; + protected final DBTrace trace; + + protected final DBCachedObjectStore overlayStore; + protected final DBCachedObjectIndex overlaysByName; + + private final Map spacesByKey = new HashMap<>(); + + public DBTraceOverlaySpaceAdapter(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock, + TaskMonitor monitor, DBTrace trace) throws VersionException, IOException { + this.dbh = dbh; + this.lock = lock; + this.trace = trace; + + DBCachedObjectStoreFactory factory = trace.getStoreFactory(); + + overlayStore = factory.getOrCreateCachedStore(DBTraceOverlaySpaceEntry.TABLE_NAME, + DBTraceOverlaySpaceEntry.class, DBTraceOverlaySpaceEntry::new, true); + overlaysByName = overlayStore.getIndex(String.class, DBTraceOverlaySpaceEntry.NAME_COLUMN); + resyncAddressFactory(); + } + + @Override + public void dbError(IOException e) { + trace.dbError(e); + } + + @Override + public void invalidateCache(boolean all) { + try (LockHold hold = LockHold.lock(lock.writeLock())) { + overlayStore.invalidateCache(); + resyncAddressFactory(); + } + } + + protected void resyncAddressFactory() { + TraceAddressFactory factory = trace.getInternalAddressFactory(); + resyncAddressFactory(factory); + } + + protected void resyncAddressFactory(TraceAddressFactory factory) { + // Clean and rename existing overlays, first + for (AddressSpace space : factory.getAllAddressSpaces()) { + if (!(space instanceof OverlayAddressSpace)) { + continue; + } + OverlayAddressSpace os = (OverlayAddressSpace) space; + DBTraceOverlaySpaceEntry ent = overlayStore.getObjectAt(os.getDatabaseKey()); + if (ent == null) { + spacesByKey.remove(os.getDatabaseKey()); + factory.removeOverlaySpace(os.getName()); + } + else if (!os.getName().equals(ent.name)) { + factory.removeOverlaySpace(os.getName()); + os.setName(ent.name); + try { + factory.addOverlayAddressSpace(os); + } + catch (DuplicateNameException e) { + throw new AssertionError(); // I just removed it + } + } + // else it's already in sync + } + // Add missing overlays + for (DBTraceOverlaySpaceEntry ent : overlayStore.asMap().values()) { + AddressSpace exists = factory.getAddressSpace(ent.name); + if (exists != null) { + // it's already in sync and/or its a physical space + continue; + } + AddressSpace baseSpace = factory.getAddressSpace(ent.baseSpace); + try { + OverlayAddressSpace space = factory.addOverlayAddressSpace(ent.name, true, + baseSpace, baseSpace.getMinAddress().getOffset(), + baseSpace.getMaxAddress().getOffset()); + space.setDatabaseKey(ent.getKey()); + spacesByKey.put(space.getDatabaseKey(), space); + } + catch (IllegalArgumentException e) { + throw new AssertionError(); // Name should be validated already, no? + } + } + } + + public AddressSpace createOverlayAddressSpace(String name, AddressSpace base) + throws DuplicateNameException { + // TODO: Exclusive lock? + try (LockHold hold = LockHold.lock(lock.writeLock())) { + TraceAddressFactory factory = trace.getInternalAddressFactory(); + if (factory.getAddressSpace(name) != null) { + throw new DuplicateNameException("Address space " + name + " already exists."); + } + + OverlayAddressSpace space = + factory.addOverlayAddressSpace(name, true, base, base.getMinAddress().getOffset(), + base.getMaxAddress().getOffset()); + // Only if it succeeds do we store the record + DBTraceOverlaySpaceEntry ent = overlayStore.create(); + ent.set(space.getName(), base.getName()); + return space; + } + } + + public void deleteOverlayAddressSpace(String name) { + // TODO: Exclusive lock? + try (LockHold hold = LockHold.lock(lock.writeLock())) { + DBTraceOverlaySpaceEntry exists = overlaysByName.getOne(name); + if (exists == null) { + throw new NoSuchElementException(name); + } + overlayStore.delete(exists); + TraceAddressFactory factory = trace.getInternalAddressFactory(); + factory.removeOverlaySpace(name); + } + } +} diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/address/TraceAddressFactory.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/address/TraceAddressFactory.java new file mode 100644 index 0000000000..1d510a2180 --- /dev/null +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/address/TraceAddressFactory.java @@ -0,0 +1,48 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.trace.database.address; + +import ghidra.program.database.ProgramAddressFactory; +import ghidra.program.model.address.AddressSpace; +import ghidra.program.model.address.OverlayAddressSpace; +import ghidra.program.model.lang.CompilerSpec; +import ghidra.program.model.lang.Language; +import ghidra.util.exception.DuplicateNameException; + +public class TraceAddressFactory extends ProgramAddressFactory { + + public TraceAddressFactory(Language language, CompilerSpec compilerSpec) { + super(language, compilerSpec); + } + + @Override // for peer access + protected OverlayAddressSpace addOverlayAddressSpace(String name, boolean preserveName, + AddressSpace originalSpace, long minOffset, long maxOffset) { + return super.addOverlayAddressSpace(name, preserveName, originalSpace, minOffset, + maxOffset); + } + + @Override // for peer access + protected void addOverlayAddressSpace(OverlayAddressSpace ovSpace) + throws DuplicateNameException { + super.addOverlayAddressSpace(ovSpace); + } + + @Override // for peer access + protected void removeOverlaySpace(String name) { + super.removeOverlaySpace(name); + } +} diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCodeManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCodeManager.java index aa0baf6bd4..094d98e33a 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCodeManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCodeManager.java @@ -15,7 +15,7 @@ */ package ghidra.trace.database.listing; -import static ghidra.lifecycle.Unfinished.*; +import static ghidra.lifecycle.Unfinished.TODO; import java.io.IOException; import java.math.BigInteger; @@ -37,8 +37,9 @@ import ghidra.program.model.mem.ByteMemBufferImpl; import ghidra.program.model.mem.MemBuffer; import ghidra.program.util.ProgramContextImpl; import ghidra.trace.database.DBTrace; -import ghidra.trace.database.DBTraceUtils.AddressDBFieldCodec; -import ghidra.trace.database.DBTraceUtils.DecodesAddresses; +import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter; +import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.AddressDBFieldCodec; +import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.DecodesAddresses; import ghidra.trace.database.data.DBTraceDataTypeManager; import ghidra.trace.database.language.DBTraceLanguageManager; import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery; @@ -109,13 +110,8 @@ public class DBTraceCodeManager } @Override - public Address decodeAddress(int space, long offset) { - Language lang = manager.languageManager.getLanguageByKey(langKey); - if (lang == null) { - throw new AssertionError( - "Database is corrupt. Missing language with key: " + langKey); - } - return manager.baseLanguage.getAddressFactory().getAddress(space, offset); + public DBTraceOverlaySpaceAdapter getOverlaySpaceAdapter() { + return manager.overlayAdapter; } void set(int langKey, byte[] bytes, byte[] context, Address address, boolean delaySlot) { @@ -175,6 +171,7 @@ public class DBTraceCodeManager protected final DBTraceLanguageManager languageManager; protected final DBTraceDataTypeManager dataTypeManager; + protected final DBTraceOverlaySpaceAdapter overlayAdapter; protected final DBTraceReferenceManager referenceManager; protected final DBCachedObjectStore protoStore; @@ -201,11 +198,12 @@ public class DBTraceCodeManager public DBTraceCodeManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock, TaskMonitor monitor, Language baseLanguage, DBTrace trace, DBTraceThreadManager threadManager, DBTraceLanguageManager languageManager, - DBTraceDataTypeManager dataTypeManager, DBTraceReferenceManager referenceManager) - throws IOException, VersionException { + DBTraceDataTypeManager dataTypeManager, DBTraceOverlaySpaceAdapter overlayAdapter, + DBTraceReferenceManager referenceManager) throws IOException, VersionException { super(NAME, dbh, openMode, lock, monitor, baseLanguage, trace, threadManager); this.languageManager = languageManager; this.dataTypeManager = dataTypeManager; + this.overlayAdapter = overlayAdapter; this.referenceManager = referenceManager; DBCachedObjectStoreFactory factory = trace.getStoreFactory(); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceMemoryManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceMemoryManager.java index 80bebe9d0c..1590f03fca 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceMemoryManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceMemoryManager.java @@ -32,6 +32,7 @@ import ghidra.program.model.address.*; import ghidra.program.model.lang.Language; import ghidra.program.model.mem.MemBuffer; import ghidra.trace.database.DBTrace; +import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter; import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery; import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager; import ghidra.trace.database.space.DBTraceDelegatingManager; @@ -50,16 +51,32 @@ import ghidra.util.task.TaskMonitor; public class DBTraceMemoryManager extends AbstractDBTraceSpaceBasedManager implements TraceMemoryManager, DBTraceDelegatingManager { + protected static final String NAME = "Memory"; + protected final DBTraceOverlaySpaceAdapter overlayAdapter; + public DBTraceMemoryManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock, TaskMonitor monitor, Language baseLanguage, DBTrace trace, - DBTraceThreadManager threadManager) throws IOException, VersionException { + DBTraceThreadManager threadManager, DBTraceOverlaySpaceAdapter overlayAdapter) + throws IOException, VersionException { super(NAME, dbh, openMode, lock, monitor, baseLanguage, trace, threadManager); + this.overlayAdapter = overlayAdapter; loadSpaces(); } + @Override + public AddressSpace createOverlayAddressSpace(String name, AddressSpace base) + throws DuplicateNameException { + return overlayAdapter.createOverlayAddressSpace(name, base); + } + + @Override + public void deleteOverlayAddressSpace(String name) { + overlayAdapter.deleteOverlayAddressSpace(name); + } + @Override protected DBTraceMemorySpace createSpace(AddressSpace space, DBTraceSpaceEntry ent) throws VersionException, IOException { diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceStaticMapping.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceStaticMapping.java index 023fcd1222..e4b334f757 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceStaticMapping.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceStaticMapping.java @@ -24,7 +24,10 @@ import com.google.common.collect.Range; import db.DBRecord; import ghidra.program.model.address.*; import ghidra.trace.database.DBTraceUtils; -import ghidra.trace.database.DBTraceUtils.*; +import ghidra.trace.database.DBTraceUtils.URLDBFieldCodec; +import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter; +import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.AddressDBFieldCodec; +import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.DecodesAddresses; import ghidra.trace.model.Trace; import ghidra.trace.model.modules.TraceStaticMapping; import ghidra.util.LockHold; @@ -73,7 +76,10 @@ public class DBTraceStaticMapping extends DBAnnotatedObject @DBAnnotatedColumn(STATIC_ADDRESS_COLUMN_NAME) static DBObjectColumn STATIC_ADDRESS_COLUMN; - @DBAnnotatedField(column = TRACE_ADDRESS_COLUMN_NAME, indexed = true, codec = AddressDBFieldCodec.class) + @DBAnnotatedField( + column = TRACE_ADDRESS_COLUMN_NAME, + indexed = true, + codec = AddressDBFieldCodec.class) private Address traceAddress; @DBAnnotatedField(column = LENGTH_COLUMN_NAME) private long length; @@ -134,8 +140,8 @@ public class DBTraceStaticMapping extends DBAnnotatedObject } @Override - public Address decodeAddress(int space, long offset) { - return manager.trace.getBaseAddressFactory().getAddress(space, offset); + public DBTraceOverlaySpaceAdapter getOverlaySpaceAdapter() { + return manager.overlayAdapter; } @Override diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceStaticMappingManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceStaticMappingManager.java index 2d56aa65fb..15b45de329 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceStaticMappingManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceStaticMappingManager.java @@ -27,6 +27,7 @@ import db.DBHandle; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressRange; import ghidra.trace.database.*; +import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter; import ghidra.trace.model.Trace.TraceStaticMappingChangeType; import ghidra.trace.model.modules.TraceConflictedMappingException; import ghidra.trace.model.modules.TraceStaticMappingManager; @@ -40,6 +41,7 @@ public class DBTraceStaticMappingManager implements TraceStaticMappingManager, D protected final DBHandle dbh; protected final ReadWriteLock lock; protected final DBTrace trace; + protected final DBTraceOverlaySpaceAdapter overlayAdapter; // TODO: Why doesn't this use the R*-Tree-based store like the others? // Perhaps I thought it was overkill.... Probably should change over. @@ -49,11 +51,14 @@ public class DBTraceStaticMappingManager implements TraceStaticMappingManager, D protected final Collection view; public DBTraceStaticMappingManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock, - TaskMonitor monitor, DBTrace trace) throws VersionException, IOException { + TaskMonitor monitor, DBTrace trace, DBTraceOverlaySpaceAdapter overlayAdapter) + throws VersionException, IOException { this.dbh = dbh; this.lock = lock; this.trace = trace; + this.overlayAdapter = overlayAdapter; + DBCachedObjectStoreFactory factory = trace.getStoreFactory(); mappingStore = factory.getOrCreateCachedStore(DBTraceStaticMapping.TABLE_NAME, DBTraceStaticMapping.class, (s, r) -> new DBTraceStaticMapping(this, s, r), true); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java index d9077ccc6f..afa5238fb6 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java @@ -58,7 +58,6 @@ import ghidra.trace.model.listing.*; import ghidra.trace.model.memory.TraceMemoryRegion; import ghidra.trace.model.memory.TraceMemoryState; import ghidra.trace.model.program.TraceProgramView; -import ghidra.trace.model.program.TraceProgramViewMemory; import ghidra.trace.model.symbol.*; import ghidra.trace.model.thread.TraceThread; import ghidra.trace.util.*; @@ -1036,7 +1035,7 @@ public class DBTraceProgramView implements TraceProgramView { } @Override - public TraceProgramViewMemory getMemory() { + public DBTraceProgramViewMemory getMemory() { return memory; } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/property/DBTraceAddressPropertyManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/property/DBTraceAddressPropertyManager.java index a0dbd43957..469ff583a9 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/property/DBTraceAddressPropertyManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/property/DBTraceAddressPropertyManager.java @@ -73,6 +73,7 @@ public class DBTraceAddressPropertyManager implements TraceAddressPropertyManage void set(String name, Class valueClass) { this.name = name; this.type = valueClass.getName(); + update(NAME_COLUMN, TYPE_COLUMN); } Class getValueClass() throws ClassNotFoundException { @@ -189,7 +190,7 @@ public class DBTraceAddressPropertyManager implements TraceAddressPropertyManage } if (valueClass != map.getValueClass()) { throw new TypeMismatchException("Property " + name + " has type " + - map.getValueClass() + ", not " + valueClass); + map.getValueClass() + ", not " + valueClass); } return (AbstractDBTracePropertyMap) map; } @@ -222,7 +223,7 @@ public class DBTraceAddressPropertyManager implements TraceAddressPropertyManage } if (!valueClass.isAssignableFrom(map.getValueClass())) { throw new TypeMismatchException("Property " + name + " has type " + - map.getValueClass() + ", which does not extend " + valueClass); + map.getValueClass() + ", which does not extend " + valueClass); } return (TracePropertyMap) map; } @@ -245,7 +246,7 @@ public class DBTraceAddressPropertyManager implements TraceAddressPropertyManage } if (!map.getValueClass().isAssignableFrom(valueClass)) { throw new TypeMismatchException("Property " + name + " has type " + - map.getValueClass() + ", which is not a super-type of " + valueClass); + map.getValueClass() + ", which is not a super-type of " + valueClass); } return (TracePropertyMap) map; } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/space/AbstractDBTraceSpaceBasedManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/space/AbstractDBTraceSpaceBasedManager.java index 456c4bcd1a..0945544dea 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/space/AbstractDBTraceSpaceBasedManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/space/AbstractDBTraceSpaceBasedManager.java @@ -127,11 +127,11 @@ public abstract class AbstractDBTraceSpaceBasedManager stackStore; protected final DBCachedObjectIndex stacksByThreadSnap; @@ -51,12 +53,14 @@ public class DBTraceStackManager implements TraceStackManager, DBTraceManager { protected final DBCachedObjectIndex framesByPC; public DBTraceStackManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock, - TaskMonitor monitor, DBTrace trace, DBTraceThreadManager threadManager) + TaskMonitor monitor, DBTrace trace, DBTraceThreadManager threadManager, + DBTraceOverlaySpaceAdapter overlayAdapter) throws VersionException, IOException { this.dbh = dbh; this.lock = lock; this.trace = trace; this.threadManager = threadManager; + this.overlayAdapter = overlayAdapter; DBCachedObjectStoreFactory factory = trace.getStoreFactory(); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/AbstractDBTraceSymbol.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/AbstractDBTraceSymbol.java index 598acbcbe7..6284a5d9fc 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/AbstractDBTraceSymbol.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/AbstractDBTraceSymbol.java @@ -34,7 +34,8 @@ import ghidra.program.model.symbol.*; import ghidra.program.util.ProgramLocation; import ghidra.trace.database.DBTrace; import ghidra.trace.database.DBTraceUtils; -import ghidra.trace.database.DBTraceUtils.DecodesAddresses; +import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter; +import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.DecodesAddresses; import ghidra.trace.database.program.DBTraceProgramView; import ghidra.trace.database.symbol.DBTraceSymbolManager.DBTraceSymbolIDEntry; import ghidra.trace.database.symbol.DBTraceSymbolManager.MySymbolTypes; @@ -160,8 +161,8 @@ public abstract class AbstractDBTraceSymbol extends DBAnnotatedObject } @Override - public Address decodeAddress(int spaceId, long offset) { - return manager.trace.getBaseAddressFactory().getAddress(spaceId, offset); + public DBTraceOverlaySpaceAdapter getOverlaySpaceAdapter() { + return manager.overlayAdapter; } @Override diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionSymbol.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionSymbol.java index 92e8d4953b..f02bc7f3bc 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionSymbol.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionSymbol.java @@ -34,8 +34,8 @@ import ghidra.program.model.listing.*; import ghidra.program.model.listing.VariableUtilities.VariableConflictHandler; import ghidra.program.model.symbol.*; import ghidra.trace.database.DBTraceUtils; -import ghidra.trace.database.DBTraceUtils.AddressDBFieldCodec; -import ghidra.trace.database.DBTraceUtils.DecodesAddresses; +import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.AddressDBFieldCodec; +import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.DecodesAddresses; import ghidra.trace.database.bookmark.DBTraceBookmarkType; import ghidra.trace.database.listing.DBTraceCommentAdapter; import ghidra.trace.database.listing.DBTraceData; @@ -152,11 +152,6 @@ public class DBTraceFunctionSymbol extends DBTraceNamespaceSymbol thunked = thunkedKey == -1 ? null : manager.functionStore.getObjectAt(thunkedKey); } - @Override - public Address decodeAddress(int spaceId, long offset) { - return manager.trace.getBaseAddressFactory().getAddress(spaceId, offset); - } - protected void set(Range lifespan, Address entryPoint, String name, DBTraceFunctionSymbol thunked, DBTraceNamespaceSymbol parent, SourceType source) { // Recall: Signature source and symbol source are different fields diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceLabelSymbol.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceLabelSymbol.java index c9db472cd4..054a42cb7a 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceLabelSymbol.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceLabelSymbol.java @@ -24,8 +24,8 @@ import ghidra.program.model.address.*; import ghidra.program.model.symbol.SourceType; import ghidra.program.model.symbol.SymbolType; import ghidra.trace.database.DBTraceUtils; -import ghidra.trace.database.DBTraceUtils.AddressDBFieldCodec; -import ghidra.trace.database.DBTraceUtils.DecodesAddresses; +import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.AddressDBFieldCodec; +import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.DecodesAddresses; import ghidra.trace.database.listing.*; import ghidra.trace.database.space.DBTraceSpaceKey; import ghidra.trace.database.thread.DBTraceThread; @@ -107,11 +107,6 @@ public class DBTraceLabelSymbol extends AbstractDBTraceSymbol this.lifespan = lifespan; } - @Override - public Address decodeAddress(int spaceId, long offset) { - return manager.trace.getBaseAddressFactory().getAddress(spaceId, offset); - } - @Override public Range getLifespan() { return lifespan; diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceManager.java index b3b6b529e8..396ec0758a 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceManager.java @@ -30,6 +30,7 @@ import ghidra.program.model.lang.Language; import ghidra.program.model.lang.Register; import ghidra.program.model.symbol.*; import ghidra.trace.database.DBTrace; +import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter; import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager; import ghidra.trace.database.space.DBTraceDelegatingManager; import ghidra.trace.database.symbol.DBTraceReferenceSpace.DBTraceReferenceEntry; @@ -49,10 +50,14 @@ public class DBTraceReferenceManager extends implements TraceReferenceManager, DBTraceDelegatingManager { public static final String NAME = "Reference"; + protected final DBTraceOverlaySpaceAdapter overlayAdapter; + public DBTraceReferenceManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock, TaskMonitor monitor, Language baseLanguage, DBTrace trace, - DBTraceThreadManager threadManager) throws VersionException, IOException { + DBTraceThreadManager threadManager, DBTraceOverlaySpaceAdapter overlayAdapter) + throws VersionException, IOException { super(NAME, dbh, openMode, lock, monitor, baseLanguage, trace, threadManager); + this.overlayAdapter = overlayAdapter; loadSpaces(); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java index 162ca73e5a..3ac634bae5 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java @@ -30,7 +30,10 @@ import ghidra.program.model.lang.Register; import ghidra.program.model.symbol.*; import ghidra.trace.database.DBTrace; import ghidra.trace.database.DBTraceUtils; -import ghidra.trace.database.DBTraceUtils.*; +import ghidra.trace.database.DBTraceUtils.RefTypeDBFieldCodec; +import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter; +import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.AddressDBFieldCodec; +import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.DecodesAddresses; import ghidra.trace.database.map.*; import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData; import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery; @@ -121,7 +124,10 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS return DBTraceUtils.tableName(TABLE_NAME, space, threadKey, frameLevel); } - @DBAnnotatedField(column = TO_ADDR_COLUMN_NAME, indexed = true, codec = AddressDBFieldCodec.class) + @DBAnnotatedField( + column = TO_ADDR_COLUMN_NAME, + indexed = true, + codec = AddressDBFieldCodec.class) protected Address toAddress; @DBAnnotatedField(column = SYMBOL_ID_COLUMN_NAME, indexed = true) protected long symbolId; // TODO: Is this at the from or to address? I think TO... @@ -146,8 +152,8 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS } @Override - public Address decodeAddress(int spaceId, long offset) { - return this.space.baseLanguage.getAddressFactory().getAddress(spaceId, offset); + public DBTraceOverlaySpaceAdapter getOverlaySpaceAdapter() { + return this.space.manager.overlayAdapter; } @Override diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceSymbolManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceSymbolManager.java index c47a1f4b8f..2f8f2532d3 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceSymbolManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceSymbolManager.java @@ -30,6 +30,7 @@ import ghidra.program.model.listing.*; import ghidra.program.model.symbol.*; import ghidra.trace.database.DBTrace; import ghidra.trace.database.DBTraceManager; +import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter; import ghidra.trace.database.data.DBTraceDataTypeManager; import ghidra.trace.database.map.*; import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData; @@ -426,6 +427,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager protected final ReadWriteLock lock; protected final DBTraceThreadManager threadManager; protected final DBTraceDataTypeManager dataTypeManager; + protected final DBTraceOverlaySpaceAdapter overlayAdapter; protected final DBTraceAddressSnapRangePropertyMap idMap; @@ -473,12 +475,14 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager public DBTraceSymbolManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock, TaskMonitor monitor, Language baseLanguage, DBTrace trace, - DBTraceThreadManager threadManager, DBTraceDataTypeManager dataTypeManager) + DBTraceThreadManager threadManager, DBTraceDataTypeManager dataTypeManager, + DBTraceOverlaySpaceAdapter overlayAdapter) throws VersionException, IOException { this.trace = trace; this.lock = lock; this.threadManager = threadManager; this.dataTypeManager = dataTypeManager; + this.overlayAdapter = overlayAdapter; DBCachedObjectStoreFactory factory = trace.getStoreFactory(); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/memory/TraceMemoryManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/memory/TraceMemoryManager.java index 0166c84d58..ef9927a5bd 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/memory/TraceMemoryManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/memory/TraceMemoryManager.java @@ -22,6 +22,7 @@ import ghidra.program.model.address.AddressSpace; import ghidra.trace.model.TraceAddressSnapRange; import ghidra.trace.model.stack.TraceStackFrame; import ghidra.trace.model.thread.TraceThread; +import ghidra.util.exception.DuplicateNameException; /** * A store of memory observations over time in a trace @@ -33,6 +34,41 @@ import ghidra.trace.model.thread.TraceThread; */ public interface TraceMemoryManager extends TraceMemoryOperations { + /** + * Create a new address space with the given name based upon the given space + * + *

+ * The purpose of overlay spaces in traces is often to store bytes for things other than memory + * or registers. Some targets may expose other byte-based storage, or provide alternative views + * of memory. + * + *

+ * NOTE: This also provides a transitional piece for recording a model (sub)tree directly into a + * trace, without mapping to a Ghidra language first. As we experiment with that mode, we will + * likely instantiate traces with the "DATA:BE:64:default" language and generate an overlay + * space named after the path of each memory being recorded. Of course, the mapping still needs + * to occur between the trace and parts of the display and during emulation. + * + * @param name the name of the new address space + * @param base the space after which this is modeled + * @return the create space + * @throws DuplicateNameException if an address space with the name already exists + */ + AddressSpace createOverlayAddressSpace(String name, AddressSpace base) + throws DuplicateNameException; + + /** + * Delete an overlay address space + * + *

+ * TODO: At the moment, this will not destroy manager spaces created for the deleted address + * space. We should assess this behavior, esp. wrt. re-creating the address space later, and + * decide whether or not to clean up. + * + * @param name the name of the address space to delete + */ + void deleteOverlayAddressSpace(String name); + /** * Obtain a memory space bound to a particular address space * diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java index 09686703b0..0079f96350 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java @@ -76,40 +76,72 @@ public class ToyDBTraceBuilder implements AutoCloseable { this.trace = new DBTrace(name, language.getDefaultCompilerSpec(), this); } - public Address addr(long offset) { - return language.getDefaultSpace().getAddress(offset); + public Address addr(AddressSpace space, long offset) { + return space.getAddress(offset); } - public Address data(long offset) { - return language.getDefaultDataSpace().getAddress(offset); + public Address addr(Language lang, long offset) { + return addr(lang.getDefaultSpace(), offset); + } + + public Address addr(long offset) { + return addr(language, offset); } public Address addr(TraceGuestLanguage lang, long offset) { return lang.getLanguage().getDefaultSpace().getAddress(offset); } + public Address data(Language lang, long offset) { + return addr(lang.getDefaultDataSpace(), offset); + } + + public Address data(long offset) { + return data(language, offset); + } + public Address data(TraceGuestLanguage lang, long offset) { - return lang.getLanguage().getDefaultDataSpace().getAddress(offset); + return data(lang.getLanguage(), offset); + } + + public AddressRange range(Address start, Address end) { + return new AddressRangeImpl(start, end); + } + + public AddressRange range(AddressSpace space, long start, long end) { + return range(addr(space, start), addr(space, end)); + } + + public AddressRange range(Language lang, long start, long end) { + return range(lang.getDefaultSpace(), start, end); } public AddressRange range(long start, long end) { - return new AddressRangeImpl(addr(start), addr(end)); + return range(language, start, end); + } + + public AddressRange range(long singleton) { + return range(singleton, singleton); } public TraceAddressSnapRange srange(long snap, long start, long end) { return new ImmutableTraceAddressSnapRange(addr(start), addr(end), snap, snap); } + public AddressRange drng(Language lang, long start, long end) { + return range(language.getDefaultDataSpace(), start, end); + } + public AddressRange drng(long start, long end) { - return new AddressRangeImpl(data(start), data(end)); + return drng(language, start, end); } public AddressRange range(TraceGuestLanguage lang, long start, long end) { - return new AddressRangeImpl(addr(lang, start), addr(lang, end)); + return range(lang.getLanguage(), start, end); } public AddressRange drng(TraceGuestLanguage lang, long start, long end) { - return new AddressRangeImpl(data(lang, start), data(lang, end)); + return drng(lang.getLanguage(), start, end); } public AddressSetView set(AddressRange... ranges) { diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/listing/DBTraceCodeManagerTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/listing/DBTraceCodeManagerTest.java index c199824753..abcf8e6aac 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/listing/DBTraceCodeManagerTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/listing/DBTraceCodeManagerTest.java @@ -32,6 +32,7 @@ import ghidra.lifecycle.Unfinished; import ghidra.program.model.address.*; import ghidra.program.model.data.*; import ghidra.program.model.lang.*; +import ghidra.program.model.listing.CodeUnit; import ghidra.program.model.listing.ContextChangeException; import ghidra.program.model.mem.MemBuffer; import ghidra.program.model.scalar.Scalar; @@ -1823,6 +1824,23 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes assertEquals(4, data.getLength()); } + @Test + public void testOverlaySpaces() throws Exception { + try (UndoableTransaction tid = b.startTransaction()) { + AddressSpace os = b.trace.getMemoryManager() + .createOverlayAddressSpace("test", + b.trace.getBaseAddressFactory().getDefaultAddressSpace()); + DBTraceCodeSpace space = manager.getCodeSpace(os, true); + + b.addInstruction(0, os.getAddress(0x4004), b.language, b.buf(0xf4, 0)); + + List all = new ArrayList<>(); + space.definedUnits().get(0, true).forEach(all::add); + assertEquals(1, all.size()); + assertEquals(os, all.get(0).getAddress().getAddressSpace()); + } + } + // TODO: Test using a context-sensitive language // TODO: Test using delay-slotted instructions (DBTraceCodemanager#instructionMax) // TODO: How are lifespans of delay-slotted instructions bound to thatof the jump? diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/memory/AbstractDBTraceMemoryManagerTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/memory/AbstractDBTraceMemoryManagerTest.java index 7f30a6dfdc..70c9d4d766 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/memory/AbstractDBTraceMemoryManagerTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/memory/AbstractDBTraceMemoryManagerTest.java @@ -1118,4 +1118,23 @@ public abstract class AbstractDBTraceMemoryManagerTest } } } + + @Test + public void testOverlaySpaces() throws Exception { + try (UndoableTransaction tid = b.startTransaction()) { + AddressSpace os = memory.createOverlayAddressSpace("test", + b.trace.getBaseAddressFactory().getDefaultAddressSpace()); + DBTraceMemorySpace space = memory.getMemorySpace(os, true); + assertEquals(4, space.putBytes(0, os.getAddress(0x4000), buf(1, 2, 3, 4))); + + ByteBuffer read = ByteBuffer.allocate(4); + // This is from original space, not overlay, so should be 0s + assertEquals(4, memory.getBytes(0, b.addr(0x4000), read)); + assertArrayEquals(arr(0, 0, 0, 0), read.array()); + read.clear(); + + assertEquals(4, space.getBytes(0, os.getAddress(0x4000), read)); + assertArrayEquals(arr(1, 2, 3, 4), read.array()); + } + } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewListingTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewListingTest.java index e359f37844..09c5cbdd84 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewListingTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewListingTest.java @@ -19,22 +19,19 @@ import static ghidra.lifecycle.Unfinished.TODO; import static org.junit.Assert.*; import java.io.IOException; -import java.nio.ByteBuffer; import java.util.*; import org.junit.*; -import com.google.common.collect.Range; - -import ghidra.program.model.address.*; +import ghidra.program.database.ProgramBuilder; +import ghidra.program.model.address.AddressSet; import ghidra.program.model.data.*; import ghidra.program.model.lang.*; import ghidra.program.model.listing.*; import ghidra.program.model.scalar.Scalar; import ghidra.program.model.util.CodeUnitInsertionException; -import ghidra.program.util.DefaultLanguageService; import ghidra.test.AbstractGhidraHeadlessIntegrationTest; -import ghidra.trace.database.DBTrace; +import ghidra.trace.database.ToyDBTraceBuilder; import ghidra.trace.database.listing.DBTraceCodeManager; import ghidra.trace.database.memory.DBTraceMemoryManager; import ghidra.util.database.UndoableTransaction; @@ -42,71 +39,13 @@ import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegrationTest { - protected Language toy; - protected DBTrace trace; - protected DBTraceProgramView view; - protected DBTraceProgramViewListing listing; // TODO: Do I want to expose the internal types? - protected DBTraceMemoryManager memory; - protected DBTraceCodeManager code; - protected Data addData(long snap, Address address, DataType type, int... bytes) - throws CodeUnitInsertionException { - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Add Data", true)) { - memory.putBytes(snap, address, buf(bytes)); - Data data = - code.definedData().create(Range.closed(snap, snap), address, type, bytes.length); - assertEquals(bytes.length, data.getLength()); - return data; - } - } + ToyDBTraceBuilder b; - protected Instruction addInstruction(long snap, Address address, int... bytes) - throws InsufficientBytesException, UnknownInstructionException, - CodeUnitInsertionException { - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Add Instruction", true)) { - memory.putBytes(snap, address, buf(bytes)); - ProcessorContext ctx = new ProgramProcessorContext( - trace.getFixedProgramView(snap).getProgramContext(), address); - InstructionPrototype prototype = - toy.parse(memory.getBufferAt(snap, address), ctx, false); - Instruction ins = - code.instructions().create(Range.closed(snap, snap), address, prototype, ctx); - assertEquals(bytes.length, ins.getLength()); - return ins; - } - } - - protected Address addr(long offset) { - return toy.getDefaultSpace().getAddress(offset); - } - - protected AddressRange rng(long min, long max) { - return new AddressRangeImpl(addr(min), addr(max)); - } - - protected AddressRange rng(long addr) { - return new AddressRangeImpl(addr(addr), addr(addr)); - } - - protected AddressSetView set(AddressRange... ranges) { - AddressSet result = new AddressSet(); - for (AddressRange r : ranges) { - result.add(r); - } - return result; - } - - protected byte[] arr(int... e) { - byte[] result = new byte[e.length]; - for (int i = 0; i < e.length; i++) { - result[i] = (byte) e[i]; - } - return result; - } - - protected ByteBuffer buf(int... e) { - return ByteBuffer.wrap(arr(e)); - } + DBTraceProgramView view; + DBTraceProgramViewListing listing; // TODO: Do I want to expose the internal types? + DBTraceMemoryManager memory; + DBTraceCodeManager code; protected static void assertUndefined(CodeUnit cu) { Data data = (Data) cu; @@ -124,19 +63,24 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra @Before public void setUpTraceProgramViewListingTest() throws LanguageNotFoundException, IOException { - toy = DefaultLanguageService.getLanguageService() - .getLanguage(new LanguageID("Toy:BE:64:default")); - trace = new DBTrace("Testing", toy.getDefaultCompilerSpec(), this); - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Initialize", true)) { - trace.getTimeManager().createSnapshot("Created"); + b = new ToyDBTraceBuilder("Testing", ProgramBuilder._TOY64_BE); + try (UndoableTransaction tid = b.startTransaction()) { + b.trace.getTimeManager().createSnapshot("Created"); } - memory = trace.getMemoryManager(); - code = trace.getCodeManager(); + memory = b.trace.getMemoryManager(); + code = b.trace.getCodeManager(); // NOTE: First snap has to exist first - view = trace.getProgramView(); + view = b.trace.getProgramView(); listing = view.getListing(); } + @After + public void tearDownTraceProgramViewListingTest() { + if (b != null) { + b.close(); + } + } + @Test public void testGetProgram() { assertEquals(view, listing.getProgram()); @@ -144,7 +88,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra @Test public void testGetTrace() { - assertEquals(trace, listing.getTrace()); + assertEquals(b.trace, listing.getTrace()); } @Test @@ -154,8 +98,11 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra @Test public void testAddData() throws CodeUnitInsertionException { - Data data = addData(0, addr(0x4000), Undefined4DataType.dataType, 1, 2, 3, 4); - assertEquals(trace.getDataTypeManager() + Data data; + try (UndoableTransaction tid = b.startTransaction()) { + data = b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4)); + } + assertEquals(b.trace.getDataTypeManager() .resolve(Undefined4DataType.dataType, DataTypeConflictHandler.DEFAULT_HANDLER), data.getDataType()); @@ -165,44 +112,62 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra @Test public void testAddInstruction() throws InsufficientBytesException, UnknownInstructionException, CodeUnitInsertionException { - Instruction ins = addInstruction(0, addr(0x4005), 0xf4, 0); + Instruction ins; + try (UndoableTransaction tid = b.startTransaction()) { + ins = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0)); + } assertEquals("ret", ins.toString()); } @Test public void testGetCodeUnitAt() throws CodeUnitInsertionException, InsufficientBytesException, UnknownInstructionException { - assertUndefined(listing.getCodeUnitAt(addr(0x4000))); - Data d4000 = addData(0, addr(0x4000), Undefined4DataType.dataType, 1, 2, 3, 4); - assertEquals(d4000, listing.getCodeUnitAt(addr(0x4000))); - assertNull(listing.getCodeUnitAt(addr(0x4001))); - assertNull(listing.getCodeUnitAt(addr(0x4002))); - assertNull(listing.getCodeUnitAt(addr(0x4003))); - assertUndefined(listing.getCodeUnitAt(addr(0x4004))); + assertUndefined(listing.getCodeUnitAt(b.addr(0x4000))); - assertUndefined(listing.getCodeUnitAt(addr(0x4005))); - Instruction i4005 = addInstruction(0, addr(0x4005), 0xf4, 0); - assertEquals(i4005, listing.getCodeUnitAt(addr(0x4005))); - assertNull(listing.getCodeUnitAt(addr(0x4006))); - assertUndefined(listing.getCodeUnitAt(addr(0x4007))); + Data d4000; + try (UndoableTransaction tid = b.startTransaction()) { + d4000 = b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4)); + } + assertEquals(d4000, listing.getCodeUnitAt(b.addr(0x4000))); + assertNull(listing.getCodeUnitAt(b.addr(0x4001))); + assertNull(listing.getCodeUnitAt(b.addr(0x4002))); + assertNull(listing.getCodeUnitAt(b.addr(0x4003))); + assertUndefined(listing.getCodeUnitAt(b.addr(0x4004))); + + assertUndefined(listing.getCodeUnitAt(b.addr(0x4005))); + + Instruction i4005; + try (UndoableTransaction tid = b.startTransaction()) { + i4005 = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0)); + } + assertEquals(i4005, listing.getCodeUnitAt(b.addr(0x4005))); + assertNull(listing.getCodeUnitAt(b.addr(0x4006))); + assertUndefined(listing.getCodeUnitAt(b.addr(0x4007))); } @Test public void testGetCodeUnitContaining() throws CodeUnitInsertionException, InsufficientBytesException, UnknownInstructionException { - assertUndefined(listing.getCodeUnitContaining(addr(0x4000))); - Data d4000 = addData(0, addr(0x4000), Undefined4DataType.dataType, 1, 2, 3, 4); - assertEquals(d4000, listing.getCodeUnitContaining(addr(0x4000))); - assertEquals(d4000, listing.getCodeUnitContaining(addr(0x4001))); - assertEquals(d4000, listing.getCodeUnitContaining(addr(0x4002))); - assertEquals(d4000, listing.getCodeUnitContaining(addr(0x4003))); - assertUndefined(listing.getCodeUnitContaining(addr(0x4004))); + assertUndefined(listing.getCodeUnitContaining(b.addr(0x4000))); - assertUndefined(listing.getCodeUnitContaining(addr(0x4005))); - Instruction i4005 = addInstruction(0, addr(0x4005), 0xf4, 0); - assertEquals(i4005, listing.getCodeUnitContaining(addr(0x4005))); - assertEquals(i4005, listing.getCodeUnitContaining(addr(0x4006))); - assertUndefined(listing.getCodeUnitAt(addr(0x4007))); + Data d4000; + try (UndoableTransaction tid = b.startTransaction()) { + d4000 = b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4)); + } + assertEquals(d4000, listing.getCodeUnitContaining(b.addr(0x4000))); + assertEquals(d4000, listing.getCodeUnitContaining(b.addr(0x4001))); + assertEquals(d4000, listing.getCodeUnitContaining(b.addr(0x4002))); + assertEquals(d4000, listing.getCodeUnitContaining(b.addr(0x4003))); + assertUndefined(listing.getCodeUnitContaining(b.addr(0x4004))); + + assertUndefined(listing.getCodeUnitContaining(b.addr(0x4005))); + Instruction i4005; + try (UndoableTransaction tid = b.startTransaction()) { + i4005 = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0)); + } + assertEquals(i4005, listing.getCodeUnitContaining(b.addr(0x4005))); + assertEquals(i4005, listing.getCodeUnitContaining(b.addr(0x4006))); + assertUndefined(listing.getCodeUnitAt(b.addr(0x4007))); } @Test @@ -210,19 +175,25 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra InsufficientBytesException, UnknownInstructionException { CodeUnit cu; - assertUndefined(cu = listing.getCodeUnitAfter(addr(0x3fff))); - assertEquals(addr(0x4000), cu.getAddress()); - Data d4000 = addData(0, addr(0x4000), Undefined4DataType.dataType, 1, 2, 3, 4); - assertEquals(d4000, listing.getCodeUnitAfter(addr(0x3fff))); - assertUndefined(cu = listing.getCodeUnitAfter(addr(0x4000))); - assertEquals(addr(0x4004), cu.getAddress()); + assertUndefined(cu = listing.getCodeUnitAfter(b.addr(0x3fff))); + assertEquals(b.addr(0x4000), cu.getAddress()); + Data d4000; + try (UndoableTransaction tid = b.startTransaction()) { + d4000 = b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4)); + } + assertEquals(d4000, listing.getCodeUnitAfter(b.addr(0x3fff))); + assertUndefined(cu = listing.getCodeUnitAfter(b.addr(0x4000))); + assertEquals(b.addr(0x4004), cu.getAddress()); - assertUndefined(cu = listing.getCodeUnitAfter(addr(0x4004))); - assertEquals(addr(0x4005), cu.getAddress()); - Instruction i4005 = addInstruction(0, addr(0x4005), 0xf4, 0); - assertEquals(i4005, listing.getCodeUnitAfter(addr(0x4004))); - assertUndefined(cu = listing.getCodeUnitAfter(addr(0x4005))); - assertEquals(addr(0x4007), cu.getAddress()); + assertUndefined(cu = listing.getCodeUnitAfter(b.addr(0x4004))); + assertEquals(b.addr(0x4005), cu.getAddress()); + Instruction i4005; + try (UndoableTransaction tid = b.startTransaction()) { + i4005 = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0)); + } + assertEquals(i4005, listing.getCodeUnitAfter(b.addr(0x4004))); + assertUndefined(cu = listing.getCodeUnitAfter(b.addr(0x4005))); + assertEquals(b.addr(0x4007), cu.getAddress()); } @Test @@ -230,19 +201,25 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra InsufficientBytesException, UnknownInstructionException { CodeUnit cu; - assertUndefined(cu = listing.getCodeUnitBefore(addr(0x4001))); - assertEquals(addr(0x4000), cu.getAddress()); - Data d4000 = addData(0, addr(0x4000), Undefined4DataType.dataType, 1, 2, 3, 4); - assertEquals(d4000, listing.getCodeUnitBefore(addr(0x4001))); - assertUndefined(cu = listing.getCodeUnitBefore(addr(0x4000))); - assertEquals(addr(0x3fff), cu.getAddress()); + assertUndefined(cu = listing.getCodeUnitBefore(b.addr(0x4001))); + assertEquals(b.addr(0x4000), cu.getAddress()); + Data d4000; + try (UndoableTransaction tid = b.startTransaction()) { + d4000 = b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4)); + } + assertEquals(d4000, listing.getCodeUnitBefore(b.addr(0x4001))); + assertUndefined(cu = listing.getCodeUnitBefore(b.addr(0x4000))); + assertEquals(b.addr(0x3fff), cu.getAddress()); - assertUndefined(cu = listing.getCodeUnitBefore(addr(0x4006))); - assertEquals(addr(0x4005), cu.getAddress()); - Instruction i4005 = addInstruction(0, addr(0x4005), 0xf4, 0); - assertEquals(i4005, listing.getCodeUnitBefore(addr(0x4006))); - assertUndefined(cu = listing.getCodeUnitBefore(addr(0x4005))); - assertEquals(addr(0x4004), cu.getAddress()); + assertUndefined(cu = listing.getCodeUnitBefore(b.addr(0x4006))); + assertEquals(b.addr(0x4005), cu.getAddress()); + Instruction i4005; + try (UndoableTransaction tid = b.startTransaction()) { + i4005 = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0)); + } + assertEquals(i4005, listing.getCodeUnitBefore(b.addr(0x4006))); + assertUndefined(cu = listing.getCodeUnitBefore(b.addr(0x4005))); + assertEquals(b.addr(0x4004), cu.getAddress()); } @Test @@ -256,7 +233,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra for (int i = 0; i < sample.size(); i++) { CodeUnit cu = sample.get(i); assertUndefined(cu); - assertEquals(addr(i), cu.getAddress()); + assertEquals(b.addr(i), cu.getAddress()); } sample = takeN(10, listing.getCodeUnits(false)); @@ -264,61 +241,65 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra for (int i = 0; i < sample.size(); i++) { CodeUnit cu = sample.get(i); assertUndefined(cu); - assertEquals(addr(-1 - i), cu.getAddress()); + assertEquals(b.addr(-1 - i), cu.getAddress()); } - sample = takeN(10, listing.getCodeUnits(addr(0x3fff), true)); + sample = takeN(10, listing.getCodeUnits(b.addr(0x3fff), true)); assertEquals(10, sample.size()); for (int i = 0; i < sample.size(); i++) { CodeUnit cu = sample.get(i); assertUndefined(cu); - assertEquals(addr(0x3fff + i), cu.getAddress()); + assertEquals(b.addr(0x3fff + i), cu.getAddress()); } - sample = takeN(10, listing.getCodeUnits(addr(0x4008), false)); + sample = takeN(10, listing.getCodeUnits(b.addr(0x4008), false)); assertEquals(10, sample.size()); for (int i = 0; i < sample.size(); i++) { CodeUnit cu = sample.get(i); assertUndefined(cu); - assertEquals(addr(0x4008 - i), cu.getAddress()); + assertEquals(b.addr(0x4008 - i), cu.getAddress()); } set = new AddressSet(); - set.add(addr(0x3ffe)); - set.add(rng(0x4000, 0x4003)); - set.add(addr(0x4005)); // Range only restricts start addresses - set.add(rng(0x4007, 0x4008)); + set.add(b.addr(0x3ffe)); + set.add(b.range(0x4000, 0x4003)); + set.add(b.addr(0x4005)); // Range only restricts start addresses + set.add(b.range(0x4007, 0x4008)); sample = takeN(10, listing.getCodeUnits(set, true)); assertEquals(8, sample.size()); - assertEquals(addr(0x3ffe), sample.get(0).getAddress()); - assertEquals(addr(0x4000), sample.get(1).getAddress()); - assertEquals(addr(0x4001), sample.get(2).getAddress()); - assertEquals(addr(0x4002), sample.get(3).getAddress()); - assertEquals(addr(0x4003), sample.get(4).getAddress()); - assertEquals(addr(0x4005), sample.get(5).getAddress()); - assertEquals(addr(0x4007), sample.get(6).getAddress()); - assertEquals(addr(0x4008), sample.get(7).getAddress()); + assertEquals(b.addr(0x3ffe), sample.get(0).getAddress()); + assertEquals(b.addr(0x4000), sample.get(1).getAddress()); + assertEquals(b.addr(0x4001), sample.get(2).getAddress()); + assertEquals(b.addr(0x4002), sample.get(3).getAddress()); + assertEquals(b.addr(0x4003), sample.get(4).getAddress()); + assertEquals(b.addr(0x4005), sample.get(5).getAddress()); + assertEquals(b.addr(0x4007), sample.get(6).getAddress()); + assertEquals(b.addr(0x4008), sample.get(7).getAddress()); sample = takeN(10, listing.getCodeUnits(set, false)); assertEquals(8, sample.size()); - assertEquals(addr(0x4008), sample.get(0).getAddress()); - assertEquals(addr(0x4007), sample.get(1).getAddress()); - assertEquals(addr(0x4005), sample.get(2).getAddress()); - assertEquals(addr(0x4003), sample.get(3).getAddress()); - assertEquals(addr(0x4002), sample.get(4).getAddress()); - assertEquals(addr(0x4001), sample.get(5).getAddress()); - assertEquals(addr(0x4000), sample.get(6).getAddress()); - assertEquals(addr(0x3ffe), sample.get(7).getAddress()); + assertEquals(b.addr(0x4008), sample.get(0).getAddress()); + assertEquals(b.addr(0x4007), sample.get(1).getAddress()); + assertEquals(b.addr(0x4005), sample.get(2).getAddress()); + assertEquals(b.addr(0x4003), sample.get(3).getAddress()); + assertEquals(b.addr(0x4002), sample.get(4).getAddress()); + assertEquals(b.addr(0x4001), sample.get(5).getAddress()); + assertEquals(b.addr(0x4000), sample.get(6).getAddress()); + assertEquals(b.addr(0x3ffe), sample.get(7).getAddress()); - Data d4000 = addData(0, addr(0x4000), Undefined4DataType.dataType, 1, 2, 3, 4); - Instruction i4005 = addInstruction(0, addr(0x4005), 0xf4, 0); + Data d4000; + Instruction i4005; + try (UndoableTransaction tid = b.startTransaction()) { + d4000 = b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4)); + i4005 = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0)); + } sample = takeN(10, listing.getCodeUnits(true)); assertEquals(10, sample.size()); for (int i = 0; i < sample.size(); i++) { CodeUnit cu = sample.get(i); assertUndefined(cu); - assertEquals(addr(i), cu.getAddress()); + assertEquals(b.addr(i), cu.getAddress()); } sample = takeN(10, listing.getCodeUnits(false)); @@ -326,84 +307,96 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra for (int i = 0; i < sample.size(); i++) { CodeUnit cu = sample.get(i); assertUndefined(cu); - assertEquals(addr(-1 - i), cu.getAddress()); + assertEquals(b.addr(-1 - i), cu.getAddress()); } - sample = takeN(5, listing.getCodeUnits(addr(0x3fff), true)); + sample = takeN(5, listing.getCodeUnits(b.addr(0x3fff), true)); assertEquals(5, sample.size()); assertUndefined(sample.get(0)); - assertEquals(addr(0x3fff), sample.get(0).getAddress()); + assertEquals(b.addr(0x3fff), sample.get(0).getAddress()); assertEquals(d4000, sample.get(1)); assertUndefined(sample.get(2)); - assertEquals(addr(0x4004), sample.get(2).getAddress()); + assertEquals(b.addr(0x4004), sample.get(2).getAddress()); assertEquals(i4005, sample.get(3)); assertUndefined(sample.get(4)); - assertEquals(addr(0x4007), sample.get(4).getAddress()); + assertEquals(b.addr(0x4007), sample.get(4).getAddress()); - sample = takeN(5, listing.getCodeUnits(addr(0x4007), false)); + sample = takeN(5, listing.getCodeUnits(b.addr(0x4007), false)); assertEquals(5, sample.size()); assertUndefined(sample.get(0)); - assertEquals(addr(0x4007), sample.get(0).getAddress()); + assertEquals(b.addr(0x4007), sample.get(0).getAddress()); assertEquals(i4005, sample.get(1)); assertUndefined(sample.get(2)); - assertEquals(addr(0x4004), sample.get(2).getAddress()); + assertEquals(b.addr(0x4004), sample.get(2).getAddress()); assertEquals(d4000, sample.get(3)); assertUndefined(sample.get(4)); - assertEquals(addr(0x3fff), sample.get(4).getAddress()); + assertEquals(b.addr(0x3fff), sample.get(4).getAddress()); sample = takeN(10, listing.getCodeUnits(set, true)); assertEquals(5, sample.size()); - assertEquals(addr(0x3ffe), sample.get(0).getAddress()); + assertEquals(b.addr(0x3ffe), sample.get(0).getAddress()); assertEquals(d4000, sample.get(1)); assertEquals(i4005, sample.get(2)); - assertEquals(addr(0x4007), sample.get(3).getAddress()); - assertEquals(addr(0x4008), sample.get(4).getAddress()); + assertEquals(b.addr(0x4007), sample.get(3).getAddress()); + assertEquals(b.addr(0x4008), sample.get(4).getAddress()); sample = takeN(10, listing.getCodeUnits(set, false)); assertEquals(5, sample.size()); - assertEquals(addr(0x4008), sample.get(0).getAddress()); - assertEquals(addr(0x4007), sample.get(1).getAddress()); + assertEquals(b.addr(0x4008), sample.get(0).getAddress()); + assertEquals(b.addr(0x4007), sample.get(1).getAddress()); assertEquals(i4005, sample.get(2)); assertEquals(d4000, sample.get(3)); - assertEquals(addr(0x3ffe), sample.get(4).getAddress()); + assertEquals(b.addr(0x3ffe), sample.get(4).getAddress()); } @Test public void testGetInstructionAt() throws InsufficientBytesException, UnknownInstructionException, CodeUnitInsertionException { - assertNull(listing.getInstructionAt(addr(0x4005))); - Instruction i4005 = addInstruction(0, addr(0x4005), 0xf4, 0); - assertEquals(i4005, listing.getInstructionAt(addr(0x4005))); - assertNull(listing.getInstructionAt(addr(0x4006))); - assertNull(listing.getInstructionAt(addr(0x4007))); + assertNull(listing.getInstructionAt(b.addr(0x4005))); + Instruction i4005; + try (UndoableTransaction tid = b.startTransaction()) { + i4005 = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0)); + } + assertEquals(i4005, listing.getInstructionAt(b.addr(0x4005))); + assertNull(listing.getInstructionAt(b.addr(0x4006))); + assertNull(listing.getInstructionAt(b.addr(0x4007))); } @Test public void testGetInstructionContaining() throws InsufficientBytesException, UnknownInstructionException, CodeUnitInsertionException { - assertNull(listing.getInstructionContaining(addr(0x4005))); - Instruction i4005 = addInstruction(0, addr(0x4005), 0xf4, 0); - assertEquals(i4005, listing.getInstructionContaining(addr(0x4005))); - assertEquals(i4005, listing.getInstructionContaining(addr(0x4006))); - assertNull(listing.getInstructionContaining(addr(0x4007))); + assertNull(listing.getInstructionContaining(b.addr(0x4005))); + Instruction i4005; + try (UndoableTransaction tid = b.startTransaction()) { + i4005 = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0)); + } + assertEquals(i4005, listing.getInstructionContaining(b.addr(0x4005))); + assertEquals(i4005, listing.getInstructionContaining(b.addr(0x4006))); + assertNull(listing.getInstructionContaining(b.addr(0x4007))); } @Test public void testGetInstructionAfter() throws InsufficientBytesException, UnknownInstructionException, CodeUnitInsertionException { - assertNull(listing.getInstructionAfter(addr(0x4004))); - Instruction i4005 = addInstruction(0, addr(0x4005), 0xf4, 0); - assertEquals(i4005, listing.getInstructionAfter(addr(0x4004))); - assertNull(listing.getInstructionAfter(addr(0x4005))); + assertNull(listing.getInstructionAfter(b.addr(0x4004))); + Instruction i4005; + try (UndoableTransaction tid = b.startTransaction()) { + i4005 = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0)); + } + assertEquals(i4005, listing.getInstructionAfter(b.addr(0x4004))); + assertNull(listing.getInstructionAfter(b.addr(0x4005))); } @Test public void testGetInstructionBefore() throws InsufficientBytesException, UnknownInstructionException, CodeUnitInsertionException { - assertNull(listing.getInstructionBefore(addr(0x4006))); - Instruction i4005 = addInstruction(0, addr(0x4005), 0xf4, 0); - assertEquals(i4005, listing.getInstructionBefore(addr(0x4006))); - assertNull(listing.getInstructionBefore(addr(0x4005))); + assertNull(listing.getInstructionBefore(b.addr(0x4006))); + Instruction i4005; + try (UndoableTransaction tid = b.startTransaction()) { + i4005 = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0)); + } + assertEquals(i4005, listing.getInstructionBefore(b.addr(0x4006))); + assertNull(listing.getInstructionBefore(b.addr(0x4005))); } @Test @@ -413,27 +406,33 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra assertTrue(takeN(10, listing.getInstructions(true)).isEmpty()); assertTrue(takeN(10, listing.getInstructions(false)).isEmpty()); - assertTrue(takeN(10, listing.getInstructions(addr(0x4006), true)).isEmpty()); - assertTrue(takeN(10, listing.getInstructions(addr(0x4008), false)).isEmpty()); + assertTrue(takeN(10, listing.getInstructions(b.addr(0x4006), true)).isEmpty()); + assertTrue(takeN(10, listing.getInstructions(b.addr(0x4008), false)).isEmpty()); set = new AddressSet(); - set.add(addr(0x3ffe)); - set.add(rng(0x4000, 0x4003)); - set.add(addr(0x4005)); // Range only restricts start addresses - set.add(rng(0x4007, 0x4008)); + set.add(b.addr(0x3ffe)); + set.add(b.range(0x4000, 0x4003)); + set.add(b.addr(0x4005)); // Range only restricts start addresses + set.add(b.range(0x4007, 0x4008)); assertTrue(takeN(10, listing.getInstructions(set, true)).isEmpty()); assertTrue(takeN(10, listing.getInstructions(set, false)).isEmpty()); - Instruction i4005 = addInstruction(0, addr(0x4005), 0xf4, 0); - Instruction i4007 = addInstruction(0, addr(0x4007), 0xf4, 0); - Instruction i400a = addInstruction(0, addr(0x400a), 0xf4, 0); - addData(0, addr(0x400c), Undefined4DataType.dataType, 1, 2, 3, 4); + Instruction i4005; + Instruction i4007; + Instruction i400a; + try (UndoableTransaction tid = b.startTransaction()) { + i4005 = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0)); + i4007 = b.addInstruction(0, b.addr(0x4007), b.language, b.buf(0xf4, 0)); + i400a = b.addInstruction(0, b.addr(0x400a), b.language, b.buf(0xf4, 0)); + b.addData(0, b.addr(0x400c), Undefined4DataType.dataType, b.buf(1, 2, 3, 4)); + } assertEquals(List.of(i4005, i4007, i400a), takeN(10, listing.getInstructions(true))); assertEquals(List.of(i400a, i4007, i4005), takeN(10, listing.getInstructions(false))); - assertEquals(List.of(i4007, i400a), takeN(10, listing.getInstructions(addr(0x4006), true))); + assertEquals(List.of(i4007, i400a), + takeN(10, listing.getInstructions(b.addr(0x4006), true))); assertEquals(List.of(i4007, i4005), - takeN(10, listing.getInstructions(addr(0x4008), false))); + takeN(10, listing.getInstructions(b.addr(0x4008), false))); assertEquals(List.of(i4005, i4007), takeN(10, listing.getInstructions(set, true))); assertEquals(List.of(i4007, i4005), takeN(10, listing.getInstructions(set, false))); @@ -442,37 +441,47 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra @Test public void testGetDataAt() throws CodeUnitInsertionException, InsufficientBytesException, UnknownInstructionException { - assertUndefined(listing.getDataAt(addr(0x4000))); - Data d4000 = addData(0, addr(0x4000), Undefined4DataType.dataType, 1, 2, 3, 4); - assertEquals(d4000, listing.getDataAt(addr(0x4000))); - assertNull(listing.getDataAt(addr(0x4001))); - assertNull(listing.getDataAt(addr(0x4002))); - assertNull(listing.getDataAt(addr(0x4003))); - assertUndefined(listing.getDataAt(addr(0x4004))); + assertUndefined(listing.getDataAt(b.addr(0x4000))); + Data d4000; + try (UndoableTransaction tid = b.startTransaction()) { + d4000 = b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4)); + } + assertEquals(d4000, listing.getDataAt(b.addr(0x4000))); + assertNull(listing.getDataAt(b.addr(0x4001))); + assertNull(listing.getDataAt(b.addr(0x4002))); + assertNull(listing.getDataAt(b.addr(0x4003))); + assertUndefined(listing.getDataAt(b.addr(0x4004))); - assertUndefined(listing.getDataAt(addr(0x4005))); - addInstruction(0, addr(0x4005), 0xf4, 0); - assertNull(listing.getDataAt(addr(0x4005))); - assertNull(listing.getDataAt(addr(0x4006))); - assertUndefined(listing.getDataAt(addr(0x4007))); + assertUndefined(listing.getDataAt(b.addr(0x4005))); + try (UndoableTransaction tid = b.startTransaction()) { + b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0)); + } + assertNull(listing.getDataAt(b.addr(0x4005))); + assertNull(listing.getDataAt(b.addr(0x4006))); + assertUndefined(listing.getDataAt(b.addr(0x4007))); } @Test public void testGetDataContaining() throws CodeUnitInsertionException, InsufficientBytesException, UnknownInstructionException { - assertUndefined(listing.getDataContaining(addr(0x4000))); - Data d4000 = addData(0, addr(0x4000), Undefined4DataType.dataType, 1, 2, 3, 4); - assertEquals(d4000, listing.getDataContaining(addr(0x4000))); - assertEquals(d4000, listing.getDataContaining(addr(0x4001))); - assertEquals(d4000, listing.getDataContaining(addr(0x4002))); - assertEquals(d4000, listing.getDataContaining(addr(0x4003))); - assertUndefined(listing.getDataContaining(addr(0x4004))); + assertUndefined(listing.getDataContaining(b.addr(0x4000))); + Data d4000; + try (UndoableTransaction tid = b.startTransaction()) { + d4000 = b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4)); + } + assertEquals(d4000, listing.getDataContaining(b.addr(0x4000))); + assertEquals(d4000, listing.getDataContaining(b.addr(0x4001))); + assertEquals(d4000, listing.getDataContaining(b.addr(0x4002))); + assertEquals(d4000, listing.getDataContaining(b.addr(0x4003))); + assertUndefined(listing.getDataContaining(b.addr(0x4004))); - assertUndefined(listing.getDataContaining(addr(0x4005))); - addInstruction(0, addr(0x4005), 0xf4, 0); - assertNull(listing.getDataContaining(addr(0x4005))); - assertNull(listing.getDataContaining(addr(0x4006))); - assertUndefined(listing.getDataContaining(addr(0x4007))); + assertUndefined(listing.getDataContaining(b.addr(0x4005))); + try (UndoableTransaction tid = b.startTransaction()) { + b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0)); + } + assertNull(listing.getDataContaining(b.addr(0x4005))); + assertNull(listing.getDataContaining(b.addr(0x4006))); + assertUndefined(listing.getDataContaining(b.addr(0x4007))); } @Test @@ -480,18 +489,23 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra UnknownInstructionException { CodeUnit cu; - assertUndefined(cu = listing.getDataAfter(addr(0x3fff))); - assertEquals(addr(0x4000), cu.getAddress()); - Data d4000 = addData(0, addr(0x4000), Undefined4DataType.dataType, 1, 2, 3, 4); - assertEquals(d4000, listing.getDataAfter(addr(0x3fff))); - assertUndefined(cu = listing.getDataAfter(addr(0x4000))); - assertEquals(addr(0x4004), cu.getAddress()); + assertUndefined(cu = listing.getDataAfter(b.addr(0x3fff))); + assertEquals(b.addr(0x4000), cu.getAddress()); + Data d4000; + try (UndoableTransaction tid = b.startTransaction()) { + d4000 = b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4)); + } + assertEquals(d4000, listing.getDataAfter(b.addr(0x3fff))); + assertUndefined(cu = listing.getDataAfter(b.addr(0x4000))); + assertEquals(b.addr(0x4004), cu.getAddress()); - assertUndefined(cu = listing.getDataAfter(addr(0x4004))); - assertEquals(addr(0x4005), cu.getAddress()); - addInstruction(0, addr(0x4005), 0xf4, 0); - assertUndefined(cu = listing.getDataAfter(addr(0x4004))); - assertEquals(addr(0x4007), cu.getAddress()); + assertUndefined(cu = listing.getDataAfter(b.addr(0x4004))); + assertEquals(b.addr(0x4005), cu.getAddress()); + try (UndoableTransaction tid = b.startTransaction()) { + b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0)); + } + assertUndefined(cu = listing.getDataAfter(b.addr(0x4004))); + assertEquals(b.addr(0x4007), cu.getAddress()); } @Test @@ -499,18 +513,23 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra UnknownInstructionException { CodeUnit cu; - assertUndefined(cu = listing.getDataBefore(addr(0x4001))); - assertEquals(addr(0x4000), cu.getAddress()); - Data d4000 = addData(0, addr(0x4000), Undefined4DataType.dataType, 1, 2, 3, 4); - assertEquals(d4000, listing.getDataBefore(addr(0x4001))); - assertUndefined(cu = listing.getDataBefore(addr(0x4000))); - assertEquals(addr(0x3fff), cu.getAddress()); + assertUndefined(cu = listing.getDataBefore(b.addr(0x4001))); + assertEquals(b.addr(0x4000), cu.getAddress()); + Data d4000; + try (UndoableTransaction tid = b.startTransaction()) { + d4000 = b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4)); + } + assertEquals(d4000, listing.getDataBefore(b.addr(0x4001))); + assertUndefined(cu = listing.getDataBefore(b.addr(0x4000))); + assertEquals(b.addr(0x3fff), cu.getAddress()); - assertUndefined(cu = listing.getDataBefore(addr(0x4006))); - assertEquals(addr(0x4005), cu.getAddress()); - addInstruction(0, addr(0x4005), 0xf4, 0); - assertUndefined(cu = listing.getDataBefore(addr(0x4007))); - assertEquals(addr(0x4004), cu.getAddress()); + assertUndefined(cu = listing.getDataBefore(b.addr(0x4006))); + assertEquals(b.addr(0x4005), cu.getAddress()); + try (UndoableTransaction tid = b.startTransaction()) { + b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0)); + } + assertUndefined(cu = listing.getDataBefore(b.addr(0x4007))); + assertEquals(b.addr(0x4004), cu.getAddress()); } @Test @@ -524,7 +543,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra for (int i = 0; i < sample.size(); i++) { CodeUnit cu = sample.get(i); assertUndefined(cu); - assertEquals(addr(i), cu.getAddress()); + assertEquals(b.addr(i), cu.getAddress()); } sample = takeN(10, listing.getData(false)); @@ -532,61 +551,64 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra for (int i = 0; i < sample.size(); i++) { CodeUnit cu = sample.get(i); assertUndefined(cu); - assertEquals(addr(-1 - i), cu.getAddress()); + assertEquals(b.addr(-1 - i), cu.getAddress()); } - sample = takeN(10, listing.getData(addr(0x3fff), true)); + sample = takeN(10, listing.getData(b.addr(0x3fff), true)); assertEquals(10, sample.size()); for (int i = 0; i < sample.size(); i++) { CodeUnit cu = sample.get(i); assertUndefined(cu); - assertEquals(addr(0x3fff + i), cu.getAddress()); + assertEquals(b.addr(0x3fff + i), cu.getAddress()); } - sample = takeN(10, listing.getData(addr(0x4008), false)); + sample = takeN(10, listing.getData(b.addr(0x4008), false)); assertEquals(10, sample.size()); for (int i = 0; i < sample.size(); i++) { CodeUnit cu = sample.get(i); assertUndefined(cu); - assertEquals(addr(0x4008 - i), cu.getAddress()); + assertEquals(b.addr(0x4008 - i), cu.getAddress()); } set = new AddressSet(); - set.add(addr(0x3ffe)); - set.add(rng(0x4000, 0x4003)); - set.add(addr(0x4005)); // Range only restricts start addresses - set.add(rng(0x4007, 0x4008)); + set.add(b.addr(0x3ffe)); + set.add(b.range(0x4000, 0x4003)); + set.add(b.addr(0x4005)); // Range only restricts start addresses + set.add(b.range(0x4007, 0x4008)); sample = takeN(10, listing.getData(set, true)); assertEquals(8, sample.size()); - assertEquals(addr(0x3ffe), sample.get(0).getAddress()); - assertEquals(addr(0x4000), sample.get(1).getAddress()); - assertEquals(addr(0x4001), sample.get(2).getAddress()); - assertEquals(addr(0x4002), sample.get(3).getAddress()); - assertEquals(addr(0x4003), sample.get(4).getAddress()); - assertEquals(addr(0x4005), sample.get(5).getAddress()); - assertEquals(addr(0x4007), sample.get(6).getAddress()); - assertEquals(addr(0x4008), sample.get(7).getAddress()); + assertEquals(b.addr(0x3ffe), sample.get(0).getAddress()); + assertEquals(b.addr(0x4000), sample.get(1).getAddress()); + assertEquals(b.addr(0x4001), sample.get(2).getAddress()); + assertEquals(b.addr(0x4002), sample.get(3).getAddress()); + assertEquals(b.addr(0x4003), sample.get(4).getAddress()); + assertEquals(b.addr(0x4005), sample.get(5).getAddress()); + assertEquals(b.addr(0x4007), sample.get(6).getAddress()); + assertEquals(b.addr(0x4008), sample.get(7).getAddress()); sample = takeN(10, listing.getData(set, false)); assertEquals(8, sample.size()); - assertEquals(addr(0x4008), sample.get(0).getAddress()); - assertEquals(addr(0x4007), sample.get(1).getAddress()); - assertEquals(addr(0x4005), sample.get(2).getAddress()); - assertEquals(addr(0x4003), sample.get(3).getAddress()); - assertEquals(addr(0x4002), sample.get(4).getAddress()); - assertEquals(addr(0x4001), sample.get(5).getAddress()); - assertEquals(addr(0x4000), sample.get(6).getAddress()); - assertEquals(addr(0x3ffe), sample.get(7).getAddress()); + assertEquals(b.addr(0x4008), sample.get(0).getAddress()); + assertEquals(b.addr(0x4007), sample.get(1).getAddress()); + assertEquals(b.addr(0x4005), sample.get(2).getAddress()); + assertEquals(b.addr(0x4003), sample.get(3).getAddress()); + assertEquals(b.addr(0x4002), sample.get(4).getAddress()); + assertEquals(b.addr(0x4001), sample.get(5).getAddress()); + assertEquals(b.addr(0x4000), sample.get(6).getAddress()); + assertEquals(b.addr(0x3ffe), sample.get(7).getAddress()); - Data d4000 = addData(0, addr(0x4000), Undefined4DataType.dataType, 1, 2, 3, 4); - addInstruction(0, addr(0x4005), 0xf4, 0); + Data d4000; + try (UndoableTransaction tid = b.startTransaction()) { + d4000 = b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4)); + b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0)); + } sample = takeN(10, listing.getData(true)); assertEquals(10, sample.size()); for (int i = 0; i < sample.size(); i++) { CodeUnit cu = sample.get(i); assertUndefined(cu); - assertEquals(addr(i), cu.getAddress()); + assertEquals(b.addr(i), cu.getAddress()); } sample = takeN(10, listing.getData(false)); @@ -594,81 +616,93 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra for (int i = 0; i < sample.size(); i++) { CodeUnit cu = sample.get(i); assertUndefined(cu); - assertEquals(addr(-1 - i), cu.getAddress()); + assertEquals(b.addr(-1 - i), cu.getAddress()); } - sample = takeN(4, listing.getData(addr(0x3fff), true)); + sample = takeN(4, listing.getData(b.addr(0x3fff), true)); assertEquals(4, sample.size()); assertUndefined(sample.get(0)); - assertEquals(addr(0x3fff), sample.get(0).getAddress()); + assertEquals(b.addr(0x3fff), sample.get(0).getAddress()); assertEquals(d4000, sample.get(1)); assertUndefined(sample.get(2)); - assertEquals(addr(0x4004), sample.get(2).getAddress()); + assertEquals(b.addr(0x4004), sample.get(2).getAddress()); assertUndefined(sample.get(3)); - assertEquals(addr(0x4007), sample.get(3).getAddress()); + assertEquals(b.addr(0x4007), sample.get(3).getAddress()); - sample = takeN(4, listing.getData(addr(0x4007), false)); + sample = takeN(4, listing.getData(b.addr(0x4007), false)); assertEquals(4, sample.size()); assertUndefined(sample.get(0)); - assertEquals(addr(0x4007), sample.get(0).getAddress()); + assertEquals(b.addr(0x4007), sample.get(0).getAddress()); assertUndefined(sample.get(1)); - assertEquals(addr(0x4004), sample.get(1).getAddress()); + assertEquals(b.addr(0x4004), sample.get(1).getAddress()); assertEquals(d4000, sample.get(2)); assertUndefined(sample.get(3)); - assertEquals(addr(0x3fff), sample.get(3).getAddress()); + assertEquals(b.addr(0x3fff), sample.get(3).getAddress()); sample = takeN(10, listing.getData(set, true)); assertEquals(4, sample.size()); - assertEquals(addr(0x3ffe), sample.get(0).getAddress()); + assertEquals(b.addr(0x3ffe), sample.get(0).getAddress()); assertEquals(d4000, sample.get(1)); - assertEquals(addr(0x4007), sample.get(2).getAddress()); - assertEquals(addr(0x4008), sample.get(3).getAddress()); + assertEquals(b.addr(0x4007), sample.get(2).getAddress()); + assertEquals(b.addr(0x4008), sample.get(3).getAddress()); sample = takeN(10, listing.getData(set, false)); assertEquals(4, sample.size()); - assertEquals(addr(0x4008), sample.get(0).getAddress()); - assertEquals(addr(0x4007), sample.get(1).getAddress()); + assertEquals(b.addr(0x4008), sample.get(0).getAddress()); + assertEquals(b.addr(0x4007), sample.get(1).getAddress()); assertEquals(d4000, sample.get(2)); - assertEquals(addr(0x3ffe), sample.get(3).getAddress()); + assertEquals(b.addr(0x3ffe), sample.get(3).getAddress()); } @Test public void testGetDefinedDataAt() throws CodeUnitInsertionException { - assertNull(listing.getDefinedDataAt(addr(0x4000))); - Data d4000 = addData(0, addr(0x4000), Undefined4DataType.dataType, 1, 2, 3, 4); - assertEquals(d4000, listing.getDefinedDataAt(addr(0x4000))); - assertNull(listing.getDefinedDataAt(addr(0x4001))); - assertNull(listing.getDefinedDataAt(addr(0x4002))); - assertNull(listing.getDefinedDataAt(addr(0x4003))); - assertNull(listing.getDefinedDataAt(addr(0x4004))); - assertNull(listing.getDefinedDataAt(addr(0x4005))); + assertNull(listing.getDefinedDataAt(b.addr(0x4000))); + Data d4000; + try (UndoableTransaction tid = b.startTransaction()) { + d4000 = b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4)); + } + assertEquals(d4000, listing.getDefinedDataAt(b.addr(0x4000))); + assertNull(listing.getDefinedDataAt(b.addr(0x4001))); + assertNull(listing.getDefinedDataAt(b.addr(0x4002))); + assertNull(listing.getDefinedDataAt(b.addr(0x4003))); + assertNull(listing.getDefinedDataAt(b.addr(0x4004))); + assertNull(listing.getDefinedDataAt(b.addr(0x4005))); } @Test public void testGetDefinedDataContaining() throws CodeUnitInsertionException { - assertNull(listing.getDefinedDataContaining(addr(0x4005))); - Data d4000 = addData(0, addr(0x4000), Undefined4DataType.dataType, 1, 2, 3, 4); - assertEquals(d4000, listing.getDefinedDataContaining(addr(0x4000))); - assertEquals(d4000, listing.getDefinedDataContaining(addr(0x4001))); - assertEquals(d4000, listing.getDefinedDataContaining(addr(0x4002))); - assertEquals(d4000, listing.getDefinedDataContaining(addr(0x4003))); - assertNull(listing.getDefinedDataContaining(addr(0x4004))); + assertNull(listing.getDefinedDataContaining(b.addr(0x4005))); + Data d4000; + try (UndoableTransaction tid = b.startTransaction()) { + d4000 = b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4)); + } + assertEquals(d4000, listing.getDefinedDataContaining(b.addr(0x4000))); + assertEquals(d4000, listing.getDefinedDataContaining(b.addr(0x4001))); + assertEquals(d4000, listing.getDefinedDataContaining(b.addr(0x4002))); + assertEquals(d4000, listing.getDefinedDataContaining(b.addr(0x4003))); + assertNull(listing.getDefinedDataContaining(b.addr(0x4004))); } @Test public void testGetDefinedDataAfter() throws CodeUnitInsertionException { - assertNull(listing.getDefinedDataAfter(addr(0x4000))); - Data d4000 = addData(0, addr(0x4000), Undefined4DataType.dataType, 1, 2, 3, 4); - assertEquals(d4000, listing.getDefinedDataAfter(addr(0x3fff))); - assertNull(listing.getDefinedDataAfter(addr(0x4000))); + assertNull(listing.getDefinedDataAfter(b.addr(0x4000))); + Data d4000; + try (UndoableTransaction tid = b.startTransaction()) { + d4000 = b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4)); + } + assertEquals(d4000, listing.getDefinedDataAfter(b.addr(0x3fff))); + assertNull(listing.getDefinedDataAfter(b.addr(0x4000))); } @Test public void testGetDefinedDataBefore() throws CodeUnitInsertionException { - assertNull(listing.getDefinedDataBefore(addr(0x4004))); - Data d4000 = addData(0, addr(0x4000), Undefined4DataType.dataType, 1, 2, 3, 4); - assertEquals(d4000, listing.getDefinedDataBefore(addr(0x4001))); - assertNull(listing.getDefinedDataBefore(addr(0x4000))); + assertNull(listing.getDefinedDataBefore(b.addr(0x4004))); + Data d4000; + try (UndoableTransaction tid = b.startTransaction()) { + d4000 = b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4)); + } + assertEquals(d4000, listing.getDefinedDataBefore(b.addr(0x4001))); + assertNull(listing.getDefinedDataBefore(b.addr(0x4000))); } @Test @@ -678,26 +712,34 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra assertTrue(takeN(10, listing.getDefinedData(true)).isEmpty()); assertTrue(takeN(10, listing.getDefinedData(false)).isEmpty()); - assertTrue(takeN(10, listing.getDefinedData(addr(0x3fff), true)).isEmpty()); - assertTrue(takeN(10, listing.getDefinedData(addr(0x4009), false)).isEmpty()); + assertTrue(takeN(10, listing.getDefinedData(b.addr(0x3fff), true)).isEmpty()); + assertTrue(takeN(10, listing.getDefinedData(b.addr(0x4009), false)).isEmpty()); set = new AddressSet(); - set.add(addr(0x3ffe)); - set.add(rng(0x4000, 0x4002)); - set.add(addr(0x4004)); - set.add(rng(0x4007, 0x4008)); + set.add(b.addr(0x3ffe)); + set.add(b.range(0x4000, 0x4002)); + set.add(b.addr(0x4004)); + set.add(b.range(0x4007, 0x4008)); assertTrue(takeN(10, listing.getDefinedData(set, true)).isEmpty()); assertTrue(takeN(10, listing.getDefinedData(set, false)).isEmpty()); - Data d4000 = addData(0, addr(0x4000), Undefined4DataType.dataType, 0, 1, 2, 3); - Data d4004 = addData(0, addr(0x4004), Undefined4DataType.dataType, 5, 6, 7, 8); - Data d400a = addData(0, addr(0x400a), Undefined4DataType.dataType, 10, 11, 12, 13); - addInstruction(0, addr(0x400e), 0xf4, 0); + Data d4000; + Data d4004; + Data d400a; + try (UndoableTransaction tid = b.startTransaction()) { + d4000 = b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(0, 1, 2, 3)); + d4004 = b.addData(0, b.addr(0x4004), Undefined4DataType.dataType, b.buf(5, 6, 7, 8)); + d400a = + b.addData(0, b.addr(0x400a), Undefined4DataType.dataType, b.buf(10, 11, 12, 13)); + b.addInstruction(0, b.addr(0x400e), b.language, b.buf(0xf4, 0)); + } assertEquals(List.of(d4000, d4004, d400a), takeN(10, listing.getDefinedData(true))); assertEquals(List.of(d400a, d4004, d4000), takeN(10, listing.getDefinedData(false))); - assertEquals(List.of(d4004, d400a), takeN(10, listing.getDefinedData(addr(0x4004), true))); - assertEquals(List.of(d4004, d4000), takeN(10, listing.getDefinedData(addr(0x4004), false))); + assertEquals(List.of(d4004, d400a), + takeN(10, listing.getDefinedData(b.addr(0x4004), true))); + assertEquals(List.of(d4004, d4000), + takeN(10, listing.getDefinedData(b.addr(0x4004), false))); assertEquals(List.of(d4000, d4004), takeN(10, listing.getDefinedData(set, true))); assertEquals(List.of(d4004, d4000), takeN(10, listing.getDefinedData(set, false))); @@ -706,19 +748,23 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra @Test public void testGetUndefinedDataAt() throws CodeUnitInsertionException, InsufficientBytesException, UnknownInstructionException { - assertUndefined(listing.getUndefinedDataAt(addr(0x4000))); - addData(0, addr(0x4000), Undefined4DataType.dataType, 1, 2, 3, 4); - assertNull(listing.getUndefinedDataAt(addr(0x4000))); - assertNull(listing.getUndefinedDataAt(addr(0x4001))); - assertNull(listing.getUndefinedDataAt(addr(0x4002))); - assertNull(listing.getUndefinedDataAt(addr(0x4003))); - assertUndefined(listing.getUndefinedDataAt(addr(0x4004))); + assertUndefined(listing.getUndefinedDataAt(b.addr(0x4000))); + try (UndoableTransaction tid = b.startTransaction()) { + b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4)); + } + assertNull(listing.getUndefinedDataAt(b.addr(0x4000))); + assertNull(listing.getUndefinedDataAt(b.addr(0x4001))); + assertNull(listing.getUndefinedDataAt(b.addr(0x4002))); + assertNull(listing.getUndefinedDataAt(b.addr(0x4003))); + assertUndefined(listing.getUndefinedDataAt(b.addr(0x4004))); - assertUndefined(listing.getUndefinedDataAt(addr(0x4005))); - addInstruction(0, addr(0x4005), 0xf4, 0); - assertNull(listing.getUndefinedDataAt(addr(0x4005))); - assertNull(listing.getUndefinedDataAt(addr(0x4006))); - assertUndefined(listing.getUndefinedDataAt(addr(0x4007))); + assertUndefined(listing.getUndefinedDataAt(b.addr(0x4005))); + try (UndoableTransaction tid = b.startTransaction()) { + b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0)); + } + assertNull(listing.getUndefinedDataAt(b.addr(0x4005))); + assertNull(listing.getUndefinedDataAt(b.addr(0x4006))); + assertUndefined(listing.getUndefinedDataAt(b.addr(0x4007))); } @Test @@ -726,17 +772,21 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra InsufficientBytesException, UnknownInstructionException { Data cu; - assertUndefined(cu = listing.getUndefinedDataAfter(addr(0x3fff), TaskMonitor.DUMMY)); - assertEquals(addr(0x4000), cu.getAddress()); - addData(0, addr(0x4000), Undefined4DataType.dataType, 1, 2, 3, 4); - assertUndefined(cu = listing.getUndefinedDataAfter(addr(0x3fff), TaskMonitor.DUMMY)); - assertEquals(addr(0x4004), cu.getAddress()); + assertUndefined(cu = listing.getUndefinedDataAfter(b.addr(0x3fff), TaskMonitor.DUMMY)); + assertEquals(b.addr(0x4000), cu.getAddress()); + try (UndoableTransaction tid = b.startTransaction()) { + b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4)); + } + assertUndefined(cu = listing.getUndefinedDataAfter(b.addr(0x3fff), TaskMonitor.DUMMY)); + assertEquals(b.addr(0x4004), cu.getAddress()); - assertUndefined(cu = listing.getUndefinedDataAfter(addr(0x4004), TaskMonitor.DUMMY)); - assertEquals(addr(0x4005), cu.getAddress()); - addInstruction(0, addr(0x4005), 0xf4, 0); - assertUndefined(cu = listing.getUndefinedDataAfter(addr(0x4004), TaskMonitor.DUMMY)); - assertEquals(addr(0x4007), cu.getAddress()); + assertUndefined(cu = listing.getUndefinedDataAfter(b.addr(0x4004), TaskMonitor.DUMMY)); + assertEquals(b.addr(0x4005), cu.getAddress()); + try (UndoableTransaction tid = b.startTransaction()) { + b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0)); + } + assertUndefined(cu = listing.getUndefinedDataAfter(b.addr(0x4004), TaskMonitor.DUMMY)); + assertEquals(b.addr(0x4007), cu.getAddress()); } @Test @@ -744,66 +794,88 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra InsufficientBytesException, UnknownInstructionException { Data cu; - assertUndefined(cu = listing.getUndefinedDataBefore(addr(0x4001), TaskMonitor.DUMMY)); - assertEquals(addr(0x4000), cu.getAddress()); - addData(0, addr(0x4000), Undefined4DataType.dataType, 1, 2, 3, 4); - assertUndefined(cu = listing.getUndefinedDataBefore(addr(0x4004), TaskMonitor.DUMMY)); - assertEquals(addr(0x3fff), cu.getAddress()); + assertUndefined(cu = listing.getUndefinedDataBefore(b.addr(0x4001), TaskMonitor.DUMMY)); + assertEquals(b.addr(0x4000), cu.getAddress()); + try (UndoableTransaction tid = b.startTransaction()) { + b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4)); + } + assertUndefined(cu = listing.getUndefinedDataBefore(b.addr(0x4004), TaskMonitor.DUMMY)); + assertEquals(b.addr(0x3fff), cu.getAddress()); - assertUndefined(cu = listing.getUndefinedDataBefore(addr(0x4006), TaskMonitor.DUMMY)); - assertEquals(addr(0x4005), cu.getAddress()); - addInstruction(0, addr(0x4005), 0xf4, 0); - assertUndefined(cu = listing.getUndefinedDataBefore(addr(0x4007), TaskMonitor.DUMMY)); - assertEquals(addr(0x4004), cu.getAddress()); + assertUndefined(cu = listing.getUndefinedDataBefore(b.addr(0x4006), TaskMonitor.DUMMY)); + assertEquals(b.addr(0x4005), cu.getAddress()); + try (UndoableTransaction tid = b.startTransaction()) { + b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0)); + } + assertUndefined(cu = listing.getUndefinedDataBefore(b.addr(0x4007), TaskMonitor.DUMMY)); + assertEquals(b.addr(0x4004), cu.getAddress()); } @Test public void testGetFirstUndefinedData() throws InsufficientBytesException, UnknownInstructionException, CodeUnitInsertionException { - addData(0, addr(0x4000), Undefined4DataType.dataType, 1, 2, 3, 4); - addInstruction(0, addr(0x4005), 0xf4, 0); + try (UndoableTransaction tid = b.startTransaction()) { + b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4)); + b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0)); + } Data cu; - assertUndefined(cu = listing.getFirstUndefinedData(set(rng(0x3fff)), TaskMonitor.DUMMY)); - assertEquals(addr(0x3fff), cu.getAddress()); + assertUndefined( + cu = listing.getFirstUndefinedData(b.set(b.range(0x3fff)), TaskMonitor.DUMMY)); + assertEquals(b.addr(0x3fff), cu.getAddress()); assertUndefined(cu = listing.getFirstUndefinedData( - set(rng(0x4000, 0x4002), rng(0x4005, 0x400a)), TaskMonitor.DUMMY)); - assertEquals(addr(0x4007), cu.getAddress()); + b.set(b.range(0x4000, 0x4002), b.range(0x4005, 0x400a)), TaskMonitor.DUMMY)); + assertEquals(b.addr(0x4007), cu.getAddress()); } @Test @Ignore("TODO") public void testGetUndefinedRanges() throws InsufficientBytesException, UnknownInstructionException, CodeUnitInsertionException, CancelledException { - addData(0, addr(0x4000), Undefined4DataType.dataType, 1, 2, 3, 4); - addInstruction(0, addr(0x4005), 0xf4, 0); + try (UndoableTransaction tid = b.startTransaction()) { + b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4)); + b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0)); + } TODO(); // Should I expect OTHER ranges in the undefined set? - assertEquals(set(rng(0, 0x3fff), rng(0x4004), rng(0x4007, -1)), listing.getUndefinedRanges( - view.getAddressFactory().getAddressSet(), false, TaskMonitor.DUMMY)); + assertEquals(b.set(b.range(0, 0x3fff), b.range(0x4004), b.range(0x4007, -1)), + listing.getUndefinedRanges( + view.getAddressFactory().getAddressSet(), false, TaskMonitor.DUMMY)); } @Test public void testGetDefinedCodeUnitAfter() throws InsufficientBytesException, UnknownInstructionException, CodeUnitInsertionException { - assertNull(listing.getDefinedCodeUnitAfter(addr(0x3fff))); - Instruction i4005 = addInstruction(0, addr(0x4005), 0xf4, 0); - assertEquals(i4005, listing.getDefinedCodeUnitAfter(addr(0x3fff))); - assertNull(listing.getDefinedCodeUnitAfter(addr(0x4005))); - Data d4000 = addData(0, addr(0x4000), Undefined4DataType.dataType, 1, 2, 3, 4); - assertEquals(d4000, listing.getDefinedCodeUnitAfter(addr(0x3fff))); - assertEquals(i4005, listing.getDefinedCodeUnitAfter(addr(0x4000))); + assertNull(listing.getDefinedCodeUnitAfter(b.addr(0x3fff))); + Instruction i4005; + try (UndoableTransaction tid = b.startTransaction()) { + i4005 = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0)); + } + assertEquals(i4005, listing.getDefinedCodeUnitAfter(b.addr(0x3fff))); + assertNull(listing.getDefinedCodeUnitAfter(b.addr(0x4005))); + Data d4000; + try (UndoableTransaction tid = b.startTransaction()) { + d4000 = b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4)); + } + assertEquals(d4000, listing.getDefinedCodeUnitAfter(b.addr(0x3fff))); + assertEquals(i4005, listing.getDefinedCodeUnitAfter(b.addr(0x4000))); } @Test public void testGetDefinedCodeUnitBefore() throws InsufficientBytesException, UnknownInstructionException, CodeUnitInsertionException { - assertNull(listing.getDefinedCodeUnitBefore(addr(0x4006))); - Data d4000 = addData(0, addr(0x4000), Undefined4DataType.dataType, 1, 2, 3, 4); - assertEquals(d4000, listing.getDefinedCodeUnitBefore(addr(0x4006))); - assertNull(listing.getDefinedCodeUnitBefore(addr(0x4000))); - Instruction i4005 = addInstruction(0, addr(0x4005), 0xf4, 0); - assertEquals(i4005, listing.getDefinedCodeUnitBefore(addr(0x4006))); - assertEquals(d4000, listing.getDefinedCodeUnitBefore(addr(0x4005))); + assertNull(listing.getDefinedCodeUnitBefore(b.addr(0x4006))); + Data d4000; + try (UndoableTransaction tid = b.startTransaction()) { + d4000 = b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4)); + } + assertEquals(d4000, listing.getDefinedCodeUnitBefore(b.addr(0x4006))); + assertNull(listing.getDefinedCodeUnitBefore(b.addr(0x4000))); + Instruction i4005; + try (UndoableTransaction tid = b.startTransaction()) { + i4005 = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0)); + } + assertEquals(i4005, listing.getDefinedCodeUnitBefore(b.addr(0x4006))); + assertEquals(d4000, listing.getDefinedCodeUnitBefore(b.addr(0x4005))); } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewMemoryTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewMemoryTest.java new file mode 100644 index 0000000000..3015a45e8b --- /dev/null +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewMemoryTest.java @@ -0,0 +1,89 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.trace.database.program; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; + +import java.io.IOException; + +import org.junit.*; + +import ghidra.program.database.ProgramBuilder; +import ghidra.program.model.address.*; +import ghidra.program.model.lang.LanguageNotFoundException; +import ghidra.program.model.mem.MemoryBlock; +import ghidra.test.AbstractGhidraHeadlessIntegrationTest; +import ghidra.trace.database.ToyDBTraceBuilder; +import ghidra.trace.database.memory.DBTraceMemoryManager; +import ghidra.trace.database.memory.DBTraceMemoryRegion; +import ghidra.trace.model.memory.TraceMemoryFlag; +import ghidra.trace.model.memory.TraceOverlappedRegionException; +import ghidra.util.database.UndoableTransaction; +import ghidra.util.exception.DuplicateNameException; + +public class DBTraceProgramViewMemoryTest extends AbstractGhidraHeadlessIntegrationTest { + + ToyDBTraceBuilder b; + + DBTraceProgramView view; + DBTraceProgramViewMemory vmem; + DBTraceMemoryManager memory; + + @Before + public void setUpTraceProgramViewMemoryTest() throws LanguageNotFoundException, IOException { + b = new ToyDBTraceBuilder("Testing", ProgramBuilder._TOY64_BE); + try (UndoableTransaction tid = b.startTransaction()) { + b.trace.getTimeManager().createSnapshot("Created"); + } + memory = b.trace.getMemoryManager(); + // NOTE: First snap has to exist first + view = b.trace.getProgramView(); + vmem = view.getMemory(); + } + + @After + public void tearDownTraceProgramViewListingTest() { + if (b != null) { + b.close(); + } + } + + @Test + public void testBlockInOverlay() throws DuplicateNameException, TraceOverlappedRegionException, + AddressOutOfBoundsException { + AddressSpace os; + DBTraceMemoryRegion io; + try (UndoableTransaction tid = b.startTransaction()) { + os = memory.createOverlayAddressSpace("test", + b.trace.getBaseAddressFactory().getDefaultAddressSpace()); + io = (DBTraceMemoryRegion) memory.createRegion(".io", 0, b.range(os, 0x1000, 0x1fff), + TraceMemoryFlag.READ, TraceMemoryFlag.WRITE, TraceMemoryFlag.VOLATILE); + } + + AddressSet asSet = new AddressSet(vmem); + assertEquals(b.set(b.range(os, 0x1000, 0x1fff)), asSet); + + MemoryBlock[] blocks = vmem.getBlocks(); + assertEquals(1, blocks.length); + + MemoryBlock blk = blocks[0]; + assertSame(blk, vmem.getBlock(io)); + assertEquals(".io", blk.getName()); + assertEquals(b.addr(os, 0x1000), blk.getStart()); + assertEquals(b.addr(os, 0x1fff), blk.getEnd()); + } +} diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/symbol/DBTraceReferenceManagerTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/symbol/DBTraceReferenceManagerTest.java index a1bf5eb119..589d64886c 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/symbol/DBTraceReferenceManagerTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/symbol/DBTraceReferenceManagerTest.java @@ -26,6 +26,7 @@ import org.junit.*; import com.google.common.collect.Range; import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressSpace; import ghidra.program.model.symbol.*; import ghidra.test.AbstractGhidraHeadlessIntegrationTest; import ghidra.trace.database.ToyDBTraceBuilder; @@ -555,4 +556,58 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati assertEquals(3, manager.getReferenceCountFrom(0, b.addr(0x4000))); } + + @Test + public void testOverlaySpaces() throws Exception { + try (UndoableTransaction tid = b.startTransaction()) { + AddressSpace os = b.trace.getMemoryManager() + .createOverlayAddressSpace("test", + b.trace.getBaseAddressFactory().getDefaultAddressSpace()); + + b.addMemoryReference(0, os.getAddress(0x4000), os.getAddress(0x5000)); + b.addMemoryReference(0, os.getAddress(0x4001), b.addr(0x5001)); + b.addMemoryReference(0, b.addr(0x4002), os.getAddress(0x5002)); + } + + File saved = b.save(); + + try (@SuppressWarnings("hiding") // On purpose + ToyDBTraceBuilder b = new ToyDBTraceBuilder(saved)) { + @SuppressWarnings("hiding") // On purpose + DBTraceReferenceManager manager = b.trace.getReferenceManager(); + + AddressSpace ds = b.trace.getBaseAddressFactory().getDefaultAddressSpace(); + AddressSpace os = b.trace.getBaseAddressFactory().getAddressSpace("test"); + assertNotNull(os); + + DBTraceReference ref; + + ref = manager.getReference(0, os.getAddress(0x4000), os.getAddress(0x5000), -1); + assertNotNull(ref); + assertEquals(os, ref.getFromAddress().getAddressSpace()); + assertEquals(os, ref.getToAddress().getAddressSpace()); + + ref = manager.getReference(0, os.getAddress(0x4001), b.addr(0x5001), -1); + assertNotNull(ref); + assertEquals(os, ref.getFromAddress().getAddressSpace()); + assertEquals(ds, ref.getToAddress().getAddressSpace()); + + ref = manager.getReference(0, b.addr(0x4002), os.getAddress(0x5002), -1); + assertNotNull(ref); + assertEquals(ds, ref.getFromAddress().getAddressSpace()); + assertEquals(os, ref.getToAddress().getAddressSpace()); + + assertEquals(0, manager.getReferenceCountFrom(0, b.addr(0x4001))); + assertEquals(1, manager.getReferenceCountFrom(0, os.getAddress(0x4001))); + + assertEquals(0, manager.getReferenceCountFrom(0, os.getAddress(0x4002))); + assertEquals(1, manager.getReferenceCountFrom(0, b.addr(0x4002))); + + assertEquals(0, manager.getReferenceCountTo(0, os.getAddress(0x5001))); + assertEquals(1, manager.getReferenceCountTo(0, b.addr(0x5001))); + + assertEquals(0, manager.getReferenceCountTo(0, b.addr(0x5002))); + assertEquals(1, manager.getReferenceCountTo(0, os.getAddress(0x5002))); + } + } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramAddressFactory.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramAddressFactory.java index cf5d646a9c..153dfbe57b 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramAddressFactory.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramAddressFactory.java @@ -97,25 +97,27 @@ public class ProgramAddressFactory extends DefaultAddressFactory { return originalFactory; } - void addOverlayAddressSpace(OverlayAddressSpace ovSpace) throws DuplicateNameException { + protected void addOverlayAddressSpace(OverlayAddressSpace ovSpace) + throws DuplicateNameException { addAddressSpace(ovSpace); } /** * Create a new OverlayAddressSpace based upon the given overlay blockName and base AddressSpace - * @param name the preferred name of the overlay address space to be created. - * This name may be modified if preserveName is false to produce a valid overlay space - * name and avoid duplication. - * @param preserveName if true specified name will be preserved, if false an unique acceptable - * overlay space name will be generated from the specified name. - * @param originalSpace the base AddressSpace to overlay + * + * @param name the preferred name of the overlay address space to be created. This name may be + * modified if preserveName is false to produce a valid overlay space name and avoid + * duplication. + * @param preserveName if true specified name will be preserved, if false an unique acceptable + * overlay space name will be generated from the specified name. + * @param originalSpace the base AddressSpace to overlay * @param minOffset the min offset of the space * @param maxOffset the max offset of the space * @return the new overlay space * @throws IllegalArgumentException if originalSpace is not permitted or preserveName is true - * and a space with specified name already exists. + * and a space with specified name already exists. */ - OverlayAddressSpace addOverlayAddressSpace(String name, boolean preserveName, + protected OverlayAddressSpace addOverlayAddressSpace(String name, boolean preserveName, AddressSpace originalSpace, long minOffset, long maxOffset) { if (!originalSpace.isMemorySpace() || originalSpace.isOverlaySpace()) { @@ -154,8 +156,8 @@ public class ProgramAddressFactory extends DefaultAddressFactory { } /** - * Get a unique address space name based on the specified - * baseOverlayName + * Get a unique address space name based on the specified baseOverlayName + * * @param baseOverlayName base overlay address space name * @return unique overlay space name */ @@ -173,12 +175,12 @@ public class ProgramAddressFactory extends DefaultAddressFactory { } /** - * Get base overlay name removing any numeric suffix which may - * have been added to avoid duplication. This method is intended - * to be used during rename only. + * Get base overlay name removing any numeric suffix which may have been added to avoid + * duplication. This method is intended to be used during rename only. + * * @param overlayName existing overlay space name - * @return base overlay name with any trailing index removed - * which may have been added to avoid duplication. + * @return base overlay name with any trailing index removed which may have been added to avoid + * duplication. */ private String getBaseOverlayName(String overlayName) { int index = overlayName.lastIndexOf('.'); @@ -200,9 +202,10 @@ public class ProgramAddressFactory extends DefaultAddressFactory { } /** - * Generate an allowed address space name from a block name. Use of unsupported - * characters will be converted to underscore (includes colon and all whitespace chars). - * double-underscore to ensure uniqueness. + * Generate an allowed address space name from a block name. Use of unsupported characters will + * be converted to underscore (includes colon and all whitespace chars). double-underscore to + * ensure uniqueness. + * * @param blockName corresponding memory block name * @return overlay space name */ @@ -249,18 +252,17 @@ public class ProgramAddressFactory extends DefaultAddressFactory { return addr; } - void removeOverlaySpace(String name) { + protected void removeOverlaySpace(String name) { removeAddressSpace(name); } /** - * Rename overlay with preferred newName. Actual name used will be returned - * and may differ from specified newName to ensure validity and avoid - * duplication. + * Rename overlay with preferred newName. Actual name used will be returned and may differ from + * specified newName to ensure validity and avoid duplication. + * * @param oldOverlaySpaceName the existing overlay address space name - * @param newName the preferred new name of the overlay address space. - * This name may be modified to produce a valid overlay space - * name to avoid duplication. + * @param newName the preferred new name of the overlay address space. This name may be modified + * to produce a valid overlay space name to avoid duplication. * @return new name applied to existing overlay space */ @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/address/OverlayAddressSpace.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/address/OverlayAddressSpace.java index 4245cc1d7e..17e8efdfe1 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/address/OverlayAddressSpace.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/address/OverlayAddressSpace.java @@ -16,17 +16,17 @@ package ghidra.program.model.address; public class OverlayAddressSpace extends AbstractAddressSpace { - public static final String OV_SEPARATER = ":"; + public static final String OV_SEPARATER = ":"; private AddressSpace originalSpace; private long databaseKey; - public OverlayAddressSpace(String name, AddressSpace originalSpace, int unique, + public OverlayAddressSpace(String name, AddressSpace originalSpace, int unique, long minOffset, long maxOffset) { super(name, originalSpace.getSize(), originalSpace.getAddressableUnitSize(), - originalSpace.getType(), unique); - + originalSpace.getType(), unique); + this.originalSpace = originalSpace; this.setShowSpaceName(true); @@ -37,7 +37,7 @@ public class OverlayAddressSpace extends AbstractAddressSpace { minAddress = new GenericAddress(this, minOffset); maxAddress = new GenericAddress(this, maxOffset); } - + // public Address addNoWrap(Address addr, long displacement) throws AddressOverflowException { // addr = super.addNoWrap(addr, displacement); // @@ -59,21 +59,22 @@ public class OverlayAddressSpace extends AbstractAddressSpace { // } // @Override - public Address getAddress(String addrString) throws AddressFormatException { + public Address getAddress(String addrString) throws AddressFormatException { addrString = addrString.replaceAll("::", ":"); int firstColonPos = addrString.indexOf(":"); int lastColonPos = addrString.lastIndexOf(":"); if (firstColonPos != lastColonPos) { - String middleName = addrString.substring(firstColonPos+1, lastColonPos); + String middleName = addrString.substring(firstColonPos + 1, lastColonPos); if (middleName.equals(originalSpace.getName())) { - addrString = addrString.substring(0, firstColonPos)+addrString.substring(lastColonPos); + addrString = + addrString.substring(0, firstColonPos) + addrString.substring(lastColonPos); } } return super.getAddress(addrString); // return translateAddress(super.getAddress(addrString)); - + } // public Address next(Address addr) { @@ -93,7 +94,7 @@ public class OverlayAddressSpace extends AbstractAddressSpace { // } @Override - public long subtract(Address addr1, Address addr2) { + public long subtract(Address addr1, Address addr2) { AddressSpace space1 = addr1.getAddressSpace(); AddressSpace space2 = addr2.getAddressSpace(); if (space1.equals(this)) { @@ -104,9 +105,9 @@ public class OverlayAddressSpace extends AbstractAddressSpace { } if (!space1.equals(space2)) { throw new IllegalArgumentException("Address are in different spaces " + - addr1.getAddressSpace().getName() + " != " + addr2.getAddressSpace().getName()); + addr1.getAddressSpace().getName() + " != " + addr2.getAddressSpace().getName()); } - return addr1.getOffset()-addr2.getOffset(); + return addr1.getOffset() - addr2.getOffset(); } // public Address subtractNoWrap(Address addr, long displacement) throws AddressOverflowException { @@ -116,59 +117,60 @@ public class OverlayAddressSpace extends AbstractAddressSpace { // public Address subtractWrap(Address addr, long displacement) { // return translateAddress(super.subtractWrap(addr, displacement)); // } - + @Override - public boolean isOverlaySpace() { + public boolean isOverlaySpace() { return originalSpace != null; } - + public AddressSpace getOverlayedSpace() { return originalSpace; } @Override - public AddressSpace getPhysicalSpace() { + public AddressSpace getPhysicalSpace() { return originalSpace.getPhysicalSpace(); } @Override - public boolean hasMappedRegisters() { + public boolean hasMappedRegisters() { return originalSpace.hasMappedRegisters(); } - + public long getMinOffset() { return minOffset; } + public long getMaxOffset() { return maxOffset; } - - public boolean contains(long offset) { - return (offset >= minOffset && offset <= maxOffset); + + public boolean contains(long offset) { + return Long.compareUnsigned(minOffset, offset) <= 0 && + Long.compareUnsigned(offset, maxOffset) <= 0; } - + @Override - public Address getAddressInThisSpaceOnly(long offset) { + public Address getAddressInThisSpaceOnly(long offset) { return new GenericAddress(offset, this); } - + @Override - public Address getAddress(long offset) { + public Address getAddress(long offset) { if (contains(offset)) { return new GenericAddress(this, offset); } return originalSpace.getAddress(offset); } - + @Override - protected Address getUncheckedAddress(long offset) { + protected Address getUncheckedAddress(long offset) { return new GenericAddress(offset, this); } - + @Override - public Address getOverlayAddress(Address addr) { - if (getOverlayedSpace().equals(addr.getAddressSpace())) - { + public Address getOverlayAddress(Address addr) { + if (getOverlayedSpace().equals(addr.getAddressSpace())) { if (contains(addr.getOffset())) { return new GenericAddress(this, addr.getOffset()); } @@ -178,25 +180,27 @@ public class OverlayAddressSpace extends AbstractAddressSpace { /** * If the given address is outside the overlay block, then the address is tranlated to an - * address in the base space with the same offset, otherwise (if the address exists in the overlay - * block), it is returned + * address in the base space with the same offset, otherwise (if the address exists in the + * overlay block), it is returned + * * @param addr the address to translate to the base space if it is outside the overlay block * @return either the given address if it is contained in the overlay memory block or an address - * in the base space with the same offset as the given address. + * in the base space with the same offset as the given address. */ public Address translateAddress(Address addr) { return translateAddress(addr, false); } + /** - * Tranlated an overlay-space address (addr, which may exceed the bounds of the overlay space) - * to an address in the base space with the same offset. - * If forceTranslation is false and addr is contained within the overlay-space - * the original addr is returned. + * Tranlated an overlay-space address (addr, which may exceed the bounds of the overlay space) + * to an address in the base space with the same offset. If forceTranslation is false and addr + * is contained within the overlay-space the original addr is returned. + * * @param addr the address to translate to the base space - * @param forceTranslation if true addr will be translated even if addr falls within the - * bounds of this overlay-space. + * @param forceTranslation if true addr will be translated even if addr falls within the bounds + * of this overlay-space. * @return either the given address if it is contained in the overlay memory block or an address - * in the base space with the same offset as the given address. + * in the base space with the same offset as the given address. */ public Address translateAddress(Address addr, boolean forceTranslation) { if (addr == null) { @@ -207,18 +211,19 @@ public class OverlayAddressSpace extends AbstractAddressSpace { } return new GenericAddress(originalSpace, addr.getOffset()); } - + /** * @return the ID of the address space underlying this space */ - public int getBaseSpaceID() { + public int getBaseSpaceID() { return originalSpace.getSpaceID(); } - + @Override - public String toString() { - return super.toString()+OV_SEPARATER; + public String toString() { + return super.toString() + OV_SEPARATER; } + public void setName(String newName) { name = newName; } @@ -226,12 +231,13 @@ public class OverlayAddressSpace extends AbstractAddressSpace { public void setDatabaseKey(long key) { databaseKey = key; } + public long getDatabaseKey() { return databaseKey; } - + @Override - public boolean equals(Object obj) { + public boolean equals(Object obj) { if (obj == this) { return true; } @@ -241,11 +247,11 @@ public class OverlayAddressSpace extends AbstractAddressSpace { if (!(obj instanceof OverlayAddressSpace)) { return false; } - OverlayAddressSpace s = (OverlayAddressSpace)obj; - - return originalSpace.equals(s.originalSpace) && - name.equals(s.name) && - minOffset == s.minOffset && - maxOffset == s.maxOffset; + OverlayAddressSpace s = (OverlayAddressSpace) obj; + + return originalSpace.equals(s.originalSpace) && + name.equals(s.name) && + minOffset == s.minOffset && + maxOffset == s.maxOffset; } }