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

View file

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

View file

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