GP-484: Added overlay spaces to Trace

This commit is contained in:
Dan 2021-10-15 11:16:01 -04:00
parent edf3a85c2d
commit 1c56c454e1
28 changed files with 1269 additions and 616 deletions

View file

@ -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;

View file

@ -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<OT extends DBAnnotatedObject & DecodesAddresses>
extends AbstractDBFieldCodec<Address, OT, BinaryField> {
public AddressDBFieldCodec(Class<OT> 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<OT extends DBAnnotatedObject>
extends AbstractDBFieldCodec<LanguageID, OT, StringField> {

View file

@ -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.
*
* <p>
* 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 <OT> the type of object containing the field
*/
public static class AddressDBFieldCodec<OT extends DBAnnotatedObject & DecodesAddresses>
extends AbstractDBFieldCodec<Address, OT, BinaryField> {
static final Charset UTF8 = Charset.forName("UTF-8");
public AddressDBFieldCodec(Class<OT> 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<DBTraceOverlaySpaceEntry> overlayStore;
protected final DBCachedObjectIndex<String, DBTraceOverlaySpaceEntry> overlaysByName;
private final Map<Long, AddressSpace> 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);
}
}
}

View file

@ -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);
}
}

View file

@ -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<DBTraceCodePrototypeEntry> 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();

View file

@ -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<DBTraceMemorySpace, DBTraceMemoryRegisterSpace>
implements TraceMemoryManager, DBTraceDelegatingManager<DBTraceMemorySpace> {
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 {

View file

@ -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

View file

@ -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<DBTraceStaticMapping> 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);

View file

@ -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;
}

View file

@ -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<T, ?>) 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<? extends T>) 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<T>) map;
}

View file

@ -127,11 +127,11 @@ public abstract class AbstractDBTraceSpaceBasedManager<M extends DBTraceSpaceBas
@SuppressWarnings("unchecked")
protected void loadSpaces() throws VersionException, IOException {
for (DBTraceSpaceEntry ent : spaceStore.asMap().values()) {
AddressFactory addressFactory = baseLanguage.getAddressFactory();
AddressFactory addressFactory = trace.getBaseAddressFactory();
AddressSpace space = addressFactory.getAddressSpace(ent.spaceName);
if (space == null) {
Msg.error(this, "Space " + ent.spaceName + " does not exist in " + baseLanguage +
". Perhaps the language changed.");
Msg.error(this, "Space " + ent.spaceName + " does not exist in trace (language=" +
baseLanguage + ").");
}
else if (space.isRegisterSpace()) {
DBTraceThread thread = threadManager.getThread(ent.threadKey);

View file

@ -21,8 +21,10 @@ import java.util.Objects;
import db.DBRecord;
import ghidra.lifecycle.Internal;
import ghidra.program.model.address.Address;
import ghidra.trace.database.DBTraceUtils.AddressDBFieldCodec;
import ghidra.trace.database.DBTraceUtils.DecodesAddresses;
import ghidra.program.model.address.AddressFactory;
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.TraceStackChangeType;
import ghidra.trace.model.stack.TraceStackFrame;
import ghidra.trace.util.TraceChangeRecord;
@ -69,8 +71,8 @@ public class DBTraceStackFrame extends DBAnnotatedObject
}
@Override
public Address decodeAddress(int space, long offset) {
return manager.trace.getBaseAddressFactory().getAddress(space, offset);
public DBTraceOverlaySpaceAdapter getOverlaySpaceAdapter() {
return manager.overlayAdapter;
}
@Override

View file

@ -24,6 +24,7 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
import ghidra.trace.database.DBTrace;
import ghidra.trace.database.DBTraceManager;
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter;
import ghidra.trace.database.stack.DBTraceStack.ThreadSnap;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.database.thread.DBTraceThreadManager;
@ -44,6 +45,7 @@ public class DBTraceStackManager implements TraceStackManager, DBTraceManager {
protected final DBTrace trace;
protected final DBTraceThreadManager threadManager;
protected final DBTraceOverlaySpaceAdapter overlayAdapter;
protected final DBCachedObjectStore<DBTraceStack> stackStore;
protected final DBCachedObjectIndex<ThreadSnap, DBTraceStack> stacksByThreadSnap;
@ -51,12 +53,14 @@ public class DBTraceStackManager implements TraceStackManager, DBTraceManager {
protected final DBCachedObjectIndex<Address, DBTraceStackFrame> 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();

View file

@ -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

View file

@ -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<Long> lifespan, Address entryPoint, String name,
DBTraceFunctionSymbol thunked, DBTraceNamespaceSymbol parent, SourceType source) {
// Recall: Signature source and symbol source are different fields

View file

@ -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<Long> getLifespan() {
return lifespan;

View file

@ -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<DBTraceReferenceSpace> {
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();
}

View file

@ -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

View file

@ -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<Long, DBTraceSymbolIDEntry> 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();

View file

@ -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
*
* <p>
* 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.
*
* <p>
* 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
*
* <p>
* 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
*

View file

@ -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) {

View file

@ -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<CodeUnit> 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?

View file

@ -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());
}
}
}

View file

@ -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());
}
}

View file

@ -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)));
}
}
}