mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
GP-484: Added overlay spaces to Trace
This commit is contained in:
parent
edf3a85c2d
commit
1c56c454e1
28 changed files with 1269 additions and 616 deletions
|
@ -27,11 +27,12 @@ import generic.depends.DependentService;
|
||||||
import generic.depends.err.ServiceConstructionException;
|
import generic.depends.err.ServiceConstructionException;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.lifecycle.Internal;
|
import ghidra.lifecycle.Internal;
|
||||||
import ghidra.program.database.ProgramAddressFactory;
|
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.util.DefaultLanguageService;
|
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.bookmark.DBTraceBookmarkManager;
|
||||||
import ghidra.trace.database.breakpoint.DBTraceBreakpointManager;
|
import ghidra.trace.database.breakpoint.DBTraceBreakpointManager;
|
||||||
import ghidra.trace.database.context.DBTraceRegisterContextManager;
|
import ghidra.trace.database.context.DBTraceRegisterContextManager;
|
||||||
|
@ -103,6 +104,8 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
||||||
@DependentService
|
@DependentService
|
||||||
protected DBTraceModuleManager moduleManager;
|
protected DBTraceModuleManager moduleManager;
|
||||||
@DependentService
|
@DependentService
|
||||||
|
protected DBTraceOverlaySpaceAdapter overlaySpaceAdapter;
|
||||||
|
@DependentService
|
||||||
protected DBTraceReferenceManager referenceManager;
|
protected DBTraceReferenceManager referenceManager;
|
||||||
@DependentService
|
@DependentService
|
||||||
protected DBTraceRegisterContextManager registerContextManager;
|
protected DBTraceRegisterContextManager registerContextManager;
|
||||||
|
@ -121,7 +124,7 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
||||||
|
|
||||||
protected Language baseLanguage;
|
protected Language baseLanguage;
|
||||||
protected CompilerSpec baseCompilerSpec;
|
protected CompilerSpec baseCompilerSpec;
|
||||||
protected AddressFactory baseAddressFactory;
|
protected TraceAddressFactory baseAddressFactory;
|
||||||
|
|
||||||
protected DBTraceChangeSet traceChangeSet;
|
protected DBTraceChangeSet traceChangeSet;
|
||||||
protected boolean recordChanges = false;
|
protected boolean recordChanges = false;
|
||||||
|
@ -142,7 +145,7 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
||||||
this.baseCompilerSpec =
|
this.baseCompilerSpec =
|
||||||
baseLanguage.getCompilerSpecByID(baseCompilerSpec.getCompilerSpecID());
|
baseLanguage.getCompilerSpecByID(baseCompilerSpec.getCompilerSpecID());
|
||||||
this.baseAddressFactory =
|
this.baseAddressFactory =
|
||||||
new ProgramAddressFactory(this.baseLanguage, this.baseCompilerSpec);
|
new TraceAddressFactory(this.baseLanguage, this.baseCompilerSpec);
|
||||||
|
|
||||||
try (UndoableTransaction tid = UndoableTransaction.start(this, "Create", false)) {
|
try (UndoableTransaction tid = UndoableTransaction.start(this, "Create", false)) {
|
||||||
initOptions(DBOpenMode.CREATE);
|
initOptions(DBOpenMode.CREATE);
|
||||||
|
@ -197,7 +200,7 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
||||||
new LanguageID(traceInfo.getString(BASE_LANGUAGE, null)));
|
new LanguageID(traceInfo.getString(BASE_LANGUAGE, null)));
|
||||||
baseCompilerSpec = baseLanguage.getCompilerSpecByID(
|
baseCompilerSpec = baseLanguage.getCompilerSpecByID(
|
||||||
new CompilerSpecID(traceInfo.getString(BASE_COMPILER, null)));
|
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) {
|
if (as == AddressSpace.OTHER_SPACE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (baseLanguage.getAddressFactory().getAddressSpace(as.getSpaceID()) != as) {
|
if (baseAddressFactory.getAddressSpace(as.getSpaceID()) != as) {
|
||||||
throw new IllegalArgumentException(
|
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
|
@DependentService
|
||||||
@SuppressWarnings("hiding")
|
|
||||||
protected DBTraceAddressPropertyManager createAddressPropertyManager(
|
protected DBTraceAddressPropertyManager createAddressPropertyManager(
|
||||||
DBTraceThreadManager threadManager) throws CancelledException, IOException {
|
DBTraceThreadManager threadManager) throws CancelledException, IOException {
|
||||||
return createTraceManager("Address Property Manager",
|
return createTraceManager("Address Property Manager",
|
||||||
|
@ -256,7 +259,6 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
||||||
}
|
}
|
||||||
|
|
||||||
@DependentService
|
@DependentService
|
||||||
@SuppressWarnings("hiding")
|
|
||||||
protected DBTraceBookmarkManager createBookmarkManager(DBTraceThreadManager threadManager)
|
protected DBTraceBookmarkManager createBookmarkManager(DBTraceThreadManager threadManager)
|
||||||
throws CancelledException, IOException {
|
throws CancelledException, IOException {
|
||||||
return createTraceManager("Bookmark Manager",
|
return createTraceManager("Bookmark Manager",
|
||||||
|
@ -265,7 +267,6 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
||||||
}
|
}
|
||||||
|
|
||||||
@DependentService
|
@DependentService
|
||||||
@SuppressWarnings("hiding")
|
|
||||||
protected DBTraceBreakpointManager createBreakpointManager(DBTraceThreadManager threadManager)
|
protected DBTraceBreakpointManager createBreakpointManager(DBTraceThreadManager threadManager)
|
||||||
throws CancelledException, IOException {
|
throws CancelledException, IOException {
|
||||||
return createTraceManager("Breakpoint Manager",
|
return createTraceManager("Breakpoint Manager",
|
||||||
|
@ -274,18 +275,17 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
||||||
}
|
}
|
||||||
|
|
||||||
@DependentService
|
@DependentService
|
||||||
@SuppressWarnings("hiding")
|
|
||||||
protected DBTraceCodeManager createCodeManager(DBTraceThreadManager threadManager,
|
protected DBTraceCodeManager createCodeManager(DBTraceThreadManager threadManager,
|
||||||
DBTraceLanguageManager languageManager, DBTraceDataTypeManager dataTypeManager,
|
DBTraceLanguageManager languageManager, DBTraceDataTypeManager dataTypeManager,
|
||||||
DBTraceReferenceManager referenceManager) throws CancelledException, IOException {
|
DBTraceOverlaySpaceAdapter overlayAdapter, DBTraceReferenceManager referenceManager)
|
||||||
|
throws CancelledException, IOException {
|
||||||
return createTraceManager("Code Manager",
|
return createTraceManager("Code Manager",
|
||||||
(openMode, monitor) -> new DBTraceCodeManager(dbh, openMode, rwLock, monitor,
|
(openMode, monitor) -> new DBTraceCodeManager(dbh, openMode, rwLock, monitor,
|
||||||
baseLanguage, this, threadManager, languageManager, dataTypeManager,
|
baseLanguage, this, threadManager, languageManager, dataTypeManager, overlayAdapter,
|
||||||
referenceManager));
|
referenceManager));
|
||||||
}
|
}
|
||||||
|
|
||||||
@DependentService
|
@DependentService
|
||||||
@SuppressWarnings("hiding")
|
|
||||||
protected DBTraceCommentAdapter createCommentAdapter(DBTraceThreadManager threadManager)
|
protected DBTraceCommentAdapter createCommentAdapter(DBTraceThreadManager threadManager)
|
||||||
throws CancelledException, IOException {
|
throws CancelledException, IOException {
|
||||||
return createTraceManager("Comment Adapter",
|
return createTraceManager("Comment Adapter",
|
||||||
|
@ -294,7 +294,6 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
||||||
}
|
}
|
||||||
|
|
||||||
@DependentService
|
@DependentService
|
||||||
@SuppressWarnings("hiding")
|
|
||||||
protected DBTraceDataSettingsAdapter createDataSettingsAdapter(
|
protected DBTraceDataSettingsAdapter createDataSettingsAdapter(
|
||||||
DBTraceThreadManager threadManager) throws CancelledException, IOException {
|
DBTraceThreadManager threadManager) throws CancelledException, IOException {
|
||||||
return createTraceManager("Data Settings Adapter",
|
return createTraceManager("Data Settings Adapter",
|
||||||
|
@ -311,8 +310,7 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
||||||
}
|
}
|
||||||
|
|
||||||
@DependentService
|
@DependentService
|
||||||
protected DBTraceEquateManager createEquateManager(
|
protected DBTraceEquateManager createEquateManager(DBTraceThreadManager threadManager)
|
||||||
@SuppressWarnings("hiding") DBTraceThreadManager threadManager)
|
|
||||||
throws CancelledException, IOException {
|
throws CancelledException, IOException {
|
||||||
return createTraceManager("Equate Manager",
|
return createTraceManager("Equate Manager",
|
||||||
(openMode, monitor) -> new DBTraceEquateManager(dbh, openMode, rwLock, monitor,
|
(openMode, monitor) -> new DBTraceEquateManager(dbh, openMode, rwLock, monitor,
|
||||||
|
@ -328,12 +326,11 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
||||||
}
|
}
|
||||||
|
|
||||||
@DependentService
|
@DependentService
|
||||||
@SuppressWarnings("hiding")
|
protected DBTraceMemoryManager createMemoryManager(DBTraceThreadManager threadManager,
|
||||||
protected DBTraceMemoryManager createMemoryManager(DBTraceThreadManager threadManager)
|
DBTraceOverlaySpaceAdapter overlayAdapter) throws IOException, CancelledException {
|
||||||
throws IOException, CancelledException {
|
|
||||||
return createTraceManager("Memory Manager",
|
return createTraceManager("Memory Manager",
|
||||||
(openMode, monitor) -> new DBTraceMemoryManager(dbh, openMode, rwLock, monitor,
|
(openMode, monitor) -> new DBTraceMemoryManager(dbh, openMode, rwLock, monitor,
|
||||||
baseLanguage, this, threadManager));
|
baseLanguage, this, threadManager, overlayAdapter));
|
||||||
}
|
}
|
||||||
|
|
||||||
@DependentService
|
@DependentService
|
||||||
|
@ -344,16 +341,22 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
||||||
}
|
}
|
||||||
|
|
||||||
@DependentService
|
@DependentService
|
||||||
@SuppressWarnings("hiding")
|
protected DBTraceOverlaySpaceAdapter createOverlaySpaceAdapter()
|
||||||
protected DBTraceReferenceManager createReferenceManager(DBTraceThreadManager threadManager)
|
|
||||||
throws CancelledException, IOException {
|
throws CancelledException, IOException {
|
||||||
return createTraceManager("Reference Manager",
|
return createTraceManager("Overlay Space Adapter",
|
||||||
(openMode, monitor) -> new DBTraceReferenceManager(dbh, openMode, rwLock, monitor,
|
(openMode, monitor) -> new DBTraceOverlaySpaceAdapter(dbh, openMode, rwLock, monitor,
|
||||||
baseLanguage, this, threadManager));
|
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
|
@DependentService
|
||||||
@SuppressWarnings("hiding")
|
|
||||||
protected DBTraceRegisterContextManager createRegisterContextManager(
|
protected DBTraceRegisterContextManager createRegisterContextManager(
|
||||||
DBTraceThreadManager threadManager, DBTraceLanguageManager languageManager)
|
DBTraceThreadManager threadManager, DBTraceLanguageManager languageManager)
|
||||||
throws CancelledException, IOException {
|
throws CancelledException, IOException {
|
||||||
|
@ -363,28 +366,28 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
||||||
}
|
}
|
||||||
|
|
||||||
@DependentService
|
@DependentService
|
||||||
@SuppressWarnings("hiding")
|
protected DBTraceStackManager createStackManager(DBTraceThreadManager threadManager,
|
||||||
protected DBTraceStackManager createStackManager(DBTraceThreadManager threadManager)
|
DBTraceOverlaySpaceAdapter overlayAdapter) throws CancelledException, IOException {
|
||||||
throws CancelledException, IOException {
|
|
||||||
return createTraceManager("Stack Manager",
|
return createTraceManager("Stack Manager",
|
||||||
(openMode, monitor) -> new DBTraceStackManager(dbh, openMode, rwLock, monitor, this,
|
(openMode, monitor) -> new DBTraceStackManager(dbh, openMode, rwLock, monitor, this,
|
||||||
threadManager));
|
threadManager, overlayAdapter));
|
||||||
}
|
}
|
||||||
|
|
||||||
@DependentService
|
@DependentService
|
||||||
protected DBTraceStaticMappingManager createStaticMappingManager()
|
protected DBTraceStaticMappingManager createStaticMappingManager(
|
||||||
throws CancelledException, IOException {
|
DBTraceOverlaySpaceAdapter overlayAdapter) throws CancelledException, IOException {
|
||||||
return createTraceManager("Static Mapping Manager", (openMode,
|
return createTraceManager("Static Mapping Manager", (openMode,
|
||||||
monitor) -> new DBTraceStaticMappingManager(dbh, openMode, rwLock, monitor, this));
|
monitor) -> new DBTraceStaticMappingManager(dbh, openMode, rwLock, monitor, this,
|
||||||
|
overlayAdapter));
|
||||||
}
|
}
|
||||||
|
|
||||||
@DependentService
|
@DependentService
|
||||||
@SuppressWarnings("hiding")
|
|
||||||
protected DBTraceSymbolManager createSymbolManager(DBTraceThreadManager threadManager,
|
protected DBTraceSymbolManager createSymbolManager(DBTraceThreadManager threadManager,
|
||||||
DBTraceDataTypeManager dataTypeManager) throws CancelledException, IOException {
|
DBTraceDataTypeManager dataTypeManager, DBTraceOverlaySpaceAdapter overlayAdapter)
|
||||||
|
throws CancelledException, IOException {
|
||||||
return createTraceManager("Symbol Manager",
|
return createTraceManager("Symbol Manager",
|
||||||
(openMode, monitor) -> new DBTraceSymbolManager(dbh, openMode, rwLock, monitor,
|
(openMode, monitor) -> new DBTraceSymbolManager(dbh, openMode, rwLock, monitor,
|
||||||
baseLanguage, this, threadManager, dataTypeManager));
|
baseLanguage, this, threadManager, dataTypeManager, overlayAdapter));
|
||||||
}
|
}
|
||||||
|
|
||||||
@DependentService
|
@DependentService
|
||||||
|
@ -394,7 +397,6 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
||||||
}
|
}
|
||||||
|
|
||||||
@DependentService
|
@DependentService
|
||||||
@SuppressWarnings("hiding")
|
|
||||||
protected DBTraceTimeManager createTimeManager(DBTraceThreadManager threadManager)
|
protected DBTraceTimeManager createTimeManager(DBTraceThreadManager threadManager)
|
||||||
throws IOException, CancelledException {
|
throws IOException, CancelledException {
|
||||||
return createTraceManager("Time Manager",
|
return createTraceManager("Time Manager",
|
||||||
|
@ -432,7 +434,12 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
||||||
return baseAddressFactory;
|
return baseAddressFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal
|
@Internal
|
||||||
|
public TraceAddressFactory getInternalAddressFactory() {
|
||||||
|
return baseAddressFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Internal
|
||||||
public DBTraceAddressPropertyManager getAddressPropertyManager() {
|
public DBTraceAddressPropertyManager getAddressPropertyManager() {
|
||||||
return addressPropertyManager;
|
return addressPropertyManager;
|
||||||
}
|
}
|
||||||
|
@ -452,12 +459,12 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
||||||
return codeManager;
|
return codeManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal
|
@Internal
|
||||||
public DBTraceCommentAdapter getCommentAdapter() {
|
public DBTraceCommentAdapter getCommentAdapter() {
|
||||||
return commentAdapter;
|
return commentAdapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal
|
@Internal
|
||||||
public DBTraceDataSettingsAdapter getDataSettingsAdapter() {
|
public DBTraceDataSettingsAdapter getDataSettingsAdapter() {
|
||||||
return dataSettingsAdapter;
|
return dataSettingsAdapter;
|
||||||
}
|
}
|
||||||
|
@ -487,6 +494,11 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
||||||
return moduleManager;
|
return moduleManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Internal
|
||||||
|
public DBTraceOverlaySpaceAdapter getOverlaySpaceAdapter() {
|
||||||
|
return overlaySpaceAdapter;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DBTraceReferenceManager getReferenceManager() {
|
public DBTraceReferenceManager getReferenceManager() {
|
||||||
return referenceManager;
|
return referenceManager;
|
||||||
|
|
|
@ -19,6 +19,7 @@ import java.lang.reflect.Field;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
@ -38,9 +39,6 @@ import ghidra.util.database.DBCachedObjectStoreFactory.AbstractDBFieldCodec;
|
||||||
|
|
||||||
public enum DBTraceUtils {
|
public enum DBTraceUtils {
|
||||||
;
|
;
|
||||||
public interface DecodesAddresses {
|
|
||||||
Address decodeAddress(int space, long offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class OffsetSnap {
|
public static class OffsetSnap {
|
||||||
public final long offset;
|
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>
|
public static class LanguageIDDBFieldCodec<OT extends DBAnnotatedObject>
|
||||||
extends AbstractDBFieldCodec<LanguageID, OT, StringField> {
|
extends AbstractDBFieldCodec<LanguageID, OT, StringField> {
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.trace.database.listing;
|
package ghidra.trace.database.listing;
|
||||||
|
|
||||||
import static ghidra.lifecycle.Unfinished.*;
|
import static ghidra.lifecycle.Unfinished.TODO;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
@ -37,8 +37,9 @@ import ghidra.program.model.mem.ByteMemBufferImpl;
|
||||||
import ghidra.program.model.mem.MemBuffer;
|
import ghidra.program.model.mem.MemBuffer;
|
||||||
import ghidra.program.util.ProgramContextImpl;
|
import ghidra.program.util.ProgramContextImpl;
|
||||||
import ghidra.trace.database.DBTrace;
|
import ghidra.trace.database.DBTrace;
|
||||||
import ghidra.trace.database.DBTraceUtils.AddressDBFieldCodec;
|
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter;
|
||||||
import ghidra.trace.database.DBTraceUtils.DecodesAddresses;
|
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.AddressDBFieldCodec;
|
||||||
|
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.DecodesAddresses;
|
||||||
import ghidra.trace.database.data.DBTraceDataTypeManager;
|
import ghidra.trace.database.data.DBTraceDataTypeManager;
|
||||||
import ghidra.trace.database.language.DBTraceLanguageManager;
|
import ghidra.trace.database.language.DBTraceLanguageManager;
|
||||||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
|
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
|
||||||
|
@ -109,13 +110,8 @@ public class DBTraceCodeManager
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address decodeAddress(int space, long offset) {
|
public DBTraceOverlaySpaceAdapter getOverlaySpaceAdapter() {
|
||||||
Language lang = manager.languageManager.getLanguageByKey(langKey);
|
return manager.overlayAdapter;
|
||||||
if (lang == null) {
|
|
||||||
throw new AssertionError(
|
|
||||||
"Database is corrupt. Missing language with key: " + langKey);
|
|
||||||
}
|
|
||||||
return manager.baseLanguage.getAddressFactory().getAddress(space, offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void set(int langKey, byte[] bytes, byte[] context, Address address, boolean delaySlot) {
|
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 DBTraceLanguageManager languageManager;
|
||||||
protected final DBTraceDataTypeManager dataTypeManager;
|
protected final DBTraceDataTypeManager dataTypeManager;
|
||||||
|
protected final DBTraceOverlaySpaceAdapter overlayAdapter;
|
||||||
protected final DBTraceReferenceManager referenceManager;
|
protected final DBTraceReferenceManager referenceManager;
|
||||||
|
|
||||||
protected final DBCachedObjectStore<DBTraceCodePrototypeEntry> protoStore;
|
protected final DBCachedObjectStore<DBTraceCodePrototypeEntry> protoStore;
|
||||||
|
@ -201,11 +198,12 @@ public class DBTraceCodeManager
|
||||||
public DBTraceCodeManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock,
|
public DBTraceCodeManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock,
|
||||||
TaskMonitor monitor, Language baseLanguage, DBTrace trace,
|
TaskMonitor monitor, Language baseLanguage, DBTrace trace,
|
||||||
DBTraceThreadManager threadManager, DBTraceLanguageManager languageManager,
|
DBTraceThreadManager threadManager, DBTraceLanguageManager languageManager,
|
||||||
DBTraceDataTypeManager dataTypeManager, DBTraceReferenceManager referenceManager)
|
DBTraceDataTypeManager dataTypeManager, DBTraceOverlaySpaceAdapter overlayAdapter,
|
||||||
throws IOException, VersionException {
|
DBTraceReferenceManager referenceManager) throws IOException, VersionException {
|
||||||
super(NAME, dbh, openMode, lock, monitor, baseLanguage, trace, threadManager);
|
super(NAME, dbh, openMode, lock, monitor, baseLanguage, trace, threadManager);
|
||||||
this.languageManager = languageManager;
|
this.languageManager = languageManager;
|
||||||
this.dataTypeManager = dataTypeManager;
|
this.dataTypeManager = dataTypeManager;
|
||||||
|
this.overlayAdapter = overlayAdapter;
|
||||||
this.referenceManager = referenceManager;
|
this.referenceManager = referenceManager;
|
||||||
|
|
||||||
DBCachedObjectStoreFactory factory = trace.getStoreFactory();
|
DBCachedObjectStoreFactory factory = trace.getStoreFactory();
|
||||||
|
|
|
@ -32,6 +32,7 @@ import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.lang.Language;
|
import ghidra.program.model.lang.Language;
|
||||||
import ghidra.program.model.mem.MemBuffer;
|
import ghidra.program.model.mem.MemBuffer;
|
||||||
import ghidra.trace.database.DBTrace;
|
import ghidra.trace.database.DBTrace;
|
||||||
|
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter;
|
||||||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
|
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
|
||||||
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager;
|
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager;
|
||||||
import ghidra.trace.database.space.DBTraceDelegatingManager;
|
import ghidra.trace.database.space.DBTraceDelegatingManager;
|
||||||
|
@ -50,16 +51,32 @@ import ghidra.util.task.TaskMonitor;
|
||||||
public class DBTraceMemoryManager
|
public class DBTraceMemoryManager
|
||||||
extends AbstractDBTraceSpaceBasedManager<DBTraceMemorySpace, DBTraceMemoryRegisterSpace>
|
extends AbstractDBTraceSpaceBasedManager<DBTraceMemorySpace, DBTraceMemoryRegisterSpace>
|
||||||
implements TraceMemoryManager, DBTraceDelegatingManager<DBTraceMemorySpace> {
|
implements TraceMemoryManager, DBTraceDelegatingManager<DBTraceMemorySpace> {
|
||||||
|
|
||||||
protected static final String NAME = "Memory";
|
protected static final String NAME = "Memory";
|
||||||
|
|
||||||
|
protected final DBTraceOverlaySpaceAdapter overlayAdapter;
|
||||||
|
|
||||||
public DBTraceMemoryManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock,
|
public DBTraceMemoryManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock,
|
||||||
TaskMonitor monitor, Language baseLanguage, DBTrace trace,
|
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);
|
super(NAME, dbh, openMode, lock, monitor, baseLanguage, trace, threadManager);
|
||||||
|
this.overlayAdapter = overlayAdapter;
|
||||||
|
|
||||||
loadSpaces();
|
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
|
@Override
|
||||||
protected DBTraceMemorySpace createSpace(AddressSpace space, DBTraceSpaceEntry ent)
|
protected DBTraceMemorySpace createSpace(AddressSpace space, DBTraceSpaceEntry ent)
|
||||||
throws VersionException, IOException {
|
throws VersionException, IOException {
|
||||||
|
|
|
@ -24,7 +24,10 @@ import com.google.common.collect.Range;
|
||||||
import db.DBRecord;
|
import db.DBRecord;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.trace.database.DBTraceUtils;
|
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.Trace;
|
||||||
import ghidra.trace.model.modules.TraceStaticMapping;
|
import ghidra.trace.model.modules.TraceStaticMapping;
|
||||||
import ghidra.util.LockHold;
|
import ghidra.util.LockHold;
|
||||||
|
@ -73,7 +76,10 @@ public class DBTraceStaticMapping extends DBAnnotatedObject
|
||||||
@DBAnnotatedColumn(STATIC_ADDRESS_COLUMN_NAME)
|
@DBAnnotatedColumn(STATIC_ADDRESS_COLUMN_NAME)
|
||||||
static DBObjectColumn STATIC_ADDRESS_COLUMN;
|
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;
|
private Address traceAddress;
|
||||||
@DBAnnotatedField(column = LENGTH_COLUMN_NAME)
|
@DBAnnotatedField(column = LENGTH_COLUMN_NAME)
|
||||||
private long length;
|
private long length;
|
||||||
|
@ -134,8 +140,8 @@ public class DBTraceStaticMapping extends DBAnnotatedObject
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address decodeAddress(int space, long offset) {
|
public DBTraceOverlaySpaceAdapter getOverlaySpaceAdapter() {
|
||||||
return manager.trace.getBaseAddressFactory().getAddress(space, offset);
|
return manager.overlayAdapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -27,6 +27,7 @@ import db.DBHandle;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressRange;
|
import ghidra.program.model.address.AddressRange;
|
||||||
import ghidra.trace.database.*;
|
import ghidra.trace.database.*;
|
||||||
|
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter;
|
||||||
import ghidra.trace.model.Trace.TraceStaticMappingChangeType;
|
import ghidra.trace.model.Trace.TraceStaticMappingChangeType;
|
||||||
import ghidra.trace.model.modules.TraceConflictedMappingException;
|
import ghidra.trace.model.modules.TraceConflictedMappingException;
|
||||||
import ghidra.trace.model.modules.TraceStaticMappingManager;
|
import ghidra.trace.model.modules.TraceStaticMappingManager;
|
||||||
|
@ -40,6 +41,7 @@ public class DBTraceStaticMappingManager implements TraceStaticMappingManager, D
|
||||||
protected final DBHandle dbh;
|
protected final DBHandle dbh;
|
||||||
protected final ReadWriteLock lock;
|
protected final ReadWriteLock lock;
|
||||||
protected final DBTrace trace;
|
protected final DBTrace trace;
|
||||||
|
protected final DBTraceOverlaySpaceAdapter overlayAdapter;
|
||||||
|
|
||||||
// TODO: Why doesn't this use the R*-Tree-based store like the others?
|
// TODO: Why doesn't this use the R*-Tree-based store like the others?
|
||||||
// Perhaps I thought it was overkill.... Probably should change over.
|
// 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;
|
protected final Collection<DBTraceStaticMapping> view;
|
||||||
|
|
||||||
public DBTraceStaticMappingManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock,
|
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.dbh = dbh;
|
||||||
this.lock = lock;
|
this.lock = lock;
|
||||||
this.trace = trace;
|
this.trace = trace;
|
||||||
|
|
||||||
|
this.overlayAdapter = overlayAdapter;
|
||||||
|
|
||||||
DBCachedObjectStoreFactory factory = trace.getStoreFactory();
|
DBCachedObjectStoreFactory factory = trace.getStoreFactory();
|
||||||
mappingStore = factory.getOrCreateCachedStore(DBTraceStaticMapping.TABLE_NAME,
|
mappingStore = factory.getOrCreateCachedStore(DBTraceStaticMapping.TABLE_NAME,
|
||||||
DBTraceStaticMapping.class, (s, r) -> new DBTraceStaticMapping(this, s, r), true);
|
DBTraceStaticMapping.class, (s, r) -> new DBTraceStaticMapping(this, s, r), true);
|
||||||
|
|
|
@ -58,7 +58,6 @@ import ghidra.trace.model.listing.*;
|
||||||
import ghidra.trace.model.memory.TraceMemoryRegion;
|
import ghidra.trace.model.memory.TraceMemoryRegion;
|
||||||
import ghidra.trace.model.memory.TraceMemoryState;
|
import ghidra.trace.model.memory.TraceMemoryState;
|
||||||
import ghidra.trace.model.program.TraceProgramView;
|
import ghidra.trace.model.program.TraceProgramView;
|
||||||
import ghidra.trace.model.program.TraceProgramViewMemory;
|
|
||||||
import ghidra.trace.model.symbol.*;
|
import ghidra.trace.model.symbol.*;
|
||||||
import ghidra.trace.model.thread.TraceThread;
|
import ghidra.trace.model.thread.TraceThread;
|
||||||
import ghidra.trace.util.*;
|
import ghidra.trace.util.*;
|
||||||
|
@ -1036,7 +1035,7 @@ public class DBTraceProgramView implements TraceProgramView {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TraceProgramViewMemory getMemory() {
|
public DBTraceProgramViewMemory getMemory() {
|
||||||
return memory;
|
return memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,7 @@ public class DBTraceAddressPropertyManager implements TraceAddressPropertyManage
|
||||||
void set(String name, Class<?> valueClass) {
|
void set(String name, Class<?> valueClass) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.type = valueClass.getName();
|
this.type = valueClass.getName();
|
||||||
|
update(NAME_COLUMN, TYPE_COLUMN);
|
||||||
}
|
}
|
||||||
|
|
||||||
Class<?> getValueClass() throws ClassNotFoundException {
|
Class<?> getValueClass() throws ClassNotFoundException {
|
||||||
|
|
|
@ -127,11 +127,11 @@ public abstract class AbstractDBTraceSpaceBasedManager<M extends DBTraceSpaceBas
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected void loadSpaces() throws VersionException, IOException {
|
protected void loadSpaces() throws VersionException, IOException {
|
||||||
for (DBTraceSpaceEntry ent : spaceStore.asMap().values()) {
|
for (DBTraceSpaceEntry ent : spaceStore.asMap().values()) {
|
||||||
AddressFactory addressFactory = baseLanguage.getAddressFactory();
|
AddressFactory addressFactory = trace.getBaseAddressFactory();
|
||||||
AddressSpace space = addressFactory.getAddressSpace(ent.spaceName);
|
AddressSpace space = addressFactory.getAddressSpace(ent.spaceName);
|
||||||
if (space == null) {
|
if (space == null) {
|
||||||
Msg.error(this, "Space " + ent.spaceName + " does not exist in " + baseLanguage +
|
Msg.error(this, "Space " + ent.spaceName + " does not exist in trace (language=" +
|
||||||
". Perhaps the language changed.");
|
baseLanguage + ").");
|
||||||
}
|
}
|
||||||
else if (space.isRegisterSpace()) {
|
else if (space.isRegisterSpace()) {
|
||||||
DBTraceThread thread = threadManager.getThread(ent.threadKey);
|
DBTraceThread thread = threadManager.getThread(ent.threadKey);
|
||||||
|
|
|
@ -21,8 +21,10 @@ import java.util.Objects;
|
||||||
import db.DBRecord;
|
import db.DBRecord;
|
||||||
import ghidra.lifecycle.Internal;
|
import ghidra.lifecycle.Internal;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.trace.database.DBTraceUtils.AddressDBFieldCodec;
|
import ghidra.program.model.address.AddressFactory;
|
||||||
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.model.Trace.TraceStackChangeType;
|
import ghidra.trace.model.Trace.TraceStackChangeType;
|
||||||
import ghidra.trace.model.stack.TraceStackFrame;
|
import ghidra.trace.model.stack.TraceStackFrame;
|
||||||
import ghidra.trace.util.TraceChangeRecord;
|
import ghidra.trace.util.TraceChangeRecord;
|
||||||
|
@ -69,8 +71,8 @@ public class DBTraceStackFrame extends DBAnnotatedObject
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address decodeAddress(int space, long offset) {
|
public DBTraceOverlaySpaceAdapter getOverlaySpaceAdapter() {
|
||||||
return manager.trace.getBaseAddressFactory().getAddress(space, offset);
|
return manager.overlayAdapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -24,6 +24,7 @@ import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressSetView;
|
import ghidra.program.model.address.AddressSetView;
|
||||||
import ghidra.trace.database.DBTrace;
|
import ghidra.trace.database.DBTrace;
|
||||||
import ghidra.trace.database.DBTraceManager;
|
import ghidra.trace.database.DBTraceManager;
|
||||||
|
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter;
|
||||||
import ghidra.trace.database.stack.DBTraceStack.ThreadSnap;
|
import ghidra.trace.database.stack.DBTraceStack.ThreadSnap;
|
||||||
import ghidra.trace.database.thread.DBTraceThread;
|
import ghidra.trace.database.thread.DBTraceThread;
|
||||||
import ghidra.trace.database.thread.DBTraceThreadManager;
|
import ghidra.trace.database.thread.DBTraceThreadManager;
|
||||||
|
@ -44,6 +45,7 @@ public class DBTraceStackManager implements TraceStackManager, DBTraceManager {
|
||||||
protected final DBTrace trace;
|
protected final DBTrace trace;
|
||||||
|
|
||||||
protected final DBTraceThreadManager threadManager;
|
protected final DBTraceThreadManager threadManager;
|
||||||
|
protected final DBTraceOverlaySpaceAdapter overlayAdapter;
|
||||||
|
|
||||||
protected final DBCachedObjectStore<DBTraceStack> stackStore;
|
protected final DBCachedObjectStore<DBTraceStack> stackStore;
|
||||||
protected final DBCachedObjectIndex<ThreadSnap, DBTraceStack> stacksByThreadSnap;
|
protected final DBCachedObjectIndex<ThreadSnap, DBTraceStack> stacksByThreadSnap;
|
||||||
|
@ -51,12 +53,14 @@ public class DBTraceStackManager implements TraceStackManager, DBTraceManager {
|
||||||
protected final DBCachedObjectIndex<Address, DBTraceStackFrame> framesByPC;
|
protected final DBCachedObjectIndex<Address, DBTraceStackFrame> framesByPC;
|
||||||
|
|
||||||
public DBTraceStackManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock,
|
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 {
|
throws VersionException, IOException {
|
||||||
this.dbh = dbh;
|
this.dbh = dbh;
|
||||||
this.lock = lock;
|
this.lock = lock;
|
||||||
this.trace = trace;
|
this.trace = trace;
|
||||||
this.threadManager = threadManager;
|
this.threadManager = threadManager;
|
||||||
|
this.overlayAdapter = overlayAdapter;
|
||||||
|
|
||||||
DBCachedObjectStoreFactory factory = trace.getStoreFactory();
|
DBCachedObjectStoreFactory factory = trace.getStoreFactory();
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,8 @@ import ghidra.program.model.symbol.*;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.trace.database.DBTrace;
|
import ghidra.trace.database.DBTrace;
|
||||||
import ghidra.trace.database.DBTraceUtils;
|
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.program.DBTraceProgramView;
|
||||||
import ghidra.trace.database.symbol.DBTraceSymbolManager.DBTraceSymbolIDEntry;
|
import ghidra.trace.database.symbol.DBTraceSymbolManager.DBTraceSymbolIDEntry;
|
||||||
import ghidra.trace.database.symbol.DBTraceSymbolManager.MySymbolTypes;
|
import ghidra.trace.database.symbol.DBTraceSymbolManager.MySymbolTypes;
|
||||||
|
@ -160,8 +161,8 @@ public abstract class AbstractDBTraceSymbol extends DBAnnotatedObject
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address decodeAddress(int spaceId, long offset) {
|
public DBTraceOverlaySpaceAdapter getOverlaySpaceAdapter() {
|
||||||
return manager.trace.getBaseAddressFactory().getAddress(spaceId, offset);
|
return manager.overlayAdapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -34,8 +34,8 @@ import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.listing.VariableUtilities.VariableConflictHandler;
|
import ghidra.program.model.listing.VariableUtilities.VariableConflictHandler;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.trace.database.DBTraceUtils;
|
import ghidra.trace.database.DBTraceUtils;
|
||||||
import ghidra.trace.database.DBTraceUtils.AddressDBFieldCodec;
|
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.AddressDBFieldCodec;
|
||||||
import ghidra.trace.database.DBTraceUtils.DecodesAddresses;
|
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.DecodesAddresses;
|
||||||
import ghidra.trace.database.bookmark.DBTraceBookmarkType;
|
import ghidra.trace.database.bookmark.DBTraceBookmarkType;
|
||||||
import ghidra.trace.database.listing.DBTraceCommentAdapter;
|
import ghidra.trace.database.listing.DBTraceCommentAdapter;
|
||||||
import ghidra.trace.database.listing.DBTraceData;
|
import ghidra.trace.database.listing.DBTraceData;
|
||||||
|
@ -152,11 +152,6 @@ public class DBTraceFunctionSymbol extends DBTraceNamespaceSymbol
|
||||||
thunked = thunkedKey == -1 ? null : manager.functionStore.getObjectAt(thunkedKey);
|
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,
|
protected void set(Range<Long> lifespan, Address entryPoint, String name,
|
||||||
DBTraceFunctionSymbol thunked, DBTraceNamespaceSymbol parent, SourceType source) {
|
DBTraceFunctionSymbol thunked, DBTraceNamespaceSymbol parent, SourceType source) {
|
||||||
// Recall: Signature source and symbol source are different fields
|
// Recall: Signature source and symbol source are different fields
|
||||||
|
|
|
@ -24,8 +24,8 @@ import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.symbol.SourceType;
|
import ghidra.program.model.symbol.SourceType;
|
||||||
import ghidra.program.model.symbol.SymbolType;
|
import ghidra.program.model.symbol.SymbolType;
|
||||||
import ghidra.trace.database.DBTraceUtils;
|
import ghidra.trace.database.DBTraceUtils;
|
||||||
import ghidra.trace.database.DBTraceUtils.AddressDBFieldCodec;
|
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.AddressDBFieldCodec;
|
||||||
import ghidra.trace.database.DBTraceUtils.DecodesAddresses;
|
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.DecodesAddresses;
|
||||||
import ghidra.trace.database.listing.*;
|
import ghidra.trace.database.listing.*;
|
||||||
import ghidra.trace.database.space.DBTraceSpaceKey;
|
import ghidra.trace.database.space.DBTraceSpaceKey;
|
||||||
import ghidra.trace.database.thread.DBTraceThread;
|
import ghidra.trace.database.thread.DBTraceThread;
|
||||||
|
@ -107,11 +107,6 @@ public class DBTraceLabelSymbol extends AbstractDBTraceSymbol
|
||||||
this.lifespan = lifespan;
|
this.lifespan = lifespan;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Address decodeAddress(int spaceId, long offset) {
|
|
||||||
return manager.trace.getBaseAddressFactory().getAddress(spaceId, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Range<Long> getLifespan() {
|
public Range<Long> getLifespan() {
|
||||||
return lifespan;
|
return lifespan;
|
||||||
|
|
|
@ -30,6 +30,7 @@ import ghidra.program.model.lang.Language;
|
||||||
import ghidra.program.model.lang.Register;
|
import ghidra.program.model.lang.Register;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.trace.database.DBTrace;
|
import ghidra.trace.database.DBTrace;
|
||||||
|
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter;
|
||||||
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager;
|
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager;
|
||||||
import ghidra.trace.database.space.DBTraceDelegatingManager;
|
import ghidra.trace.database.space.DBTraceDelegatingManager;
|
||||||
import ghidra.trace.database.symbol.DBTraceReferenceSpace.DBTraceReferenceEntry;
|
import ghidra.trace.database.symbol.DBTraceReferenceSpace.DBTraceReferenceEntry;
|
||||||
|
@ -49,10 +50,14 @@ public class DBTraceReferenceManager extends
|
||||||
implements TraceReferenceManager, DBTraceDelegatingManager<DBTraceReferenceSpace> {
|
implements TraceReferenceManager, DBTraceDelegatingManager<DBTraceReferenceSpace> {
|
||||||
public static final String NAME = "Reference";
|
public static final String NAME = "Reference";
|
||||||
|
|
||||||
|
protected final DBTraceOverlaySpaceAdapter overlayAdapter;
|
||||||
|
|
||||||
public DBTraceReferenceManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock,
|
public DBTraceReferenceManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock,
|
||||||
TaskMonitor monitor, Language baseLanguage, DBTrace trace,
|
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);
|
super(NAME, dbh, openMode, lock, monitor, baseLanguage, trace, threadManager);
|
||||||
|
this.overlayAdapter = overlayAdapter;
|
||||||
|
|
||||||
loadSpaces();
|
loadSpaces();
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,10 @@ import ghidra.program.model.lang.Register;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.trace.database.DBTrace;
|
import ghidra.trace.database.DBTrace;
|
||||||
import ghidra.trace.database.DBTraceUtils;
|
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.*;
|
||||||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData;
|
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData;
|
||||||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
|
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);
|
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;
|
protected Address toAddress;
|
||||||
@DBAnnotatedField(column = SYMBOL_ID_COLUMN_NAME, indexed = true)
|
@DBAnnotatedField(column = SYMBOL_ID_COLUMN_NAME, indexed = true)
|
||||||
protected long symbolId; // TODO: Is this at the from or to address? I think TO...
|
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
|
@Override
|
||||||
public Address decodeAddress(int spaceId, long offset) {
|
public DBTraceOverlaySpaceAdapter getOverlaySpaceAdapter() {
|
||||||
return this.space.baseLanguage.getAddressFactory().getAddress(spaceId, offset);
|
return this.space.manager.overlayAdapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -30,6 +30,7 @@ import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.trace.database.DBTrace;
|
import ghidra.trace.database.DBTrace;
|
||||||
import ghidra.trace.database.DBTraceManager;
|
import ghidra.trace.database.DBTraceManager;
|
||||||
|
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter;
|
||||||
import ghidra.trace.database.data.DBTraceDataTypeManager;
|
import ghidra.trace.database.data.DBTraceDataTypeManager;
|
||||||
import ghidra.trace.database.map.*;
|
import ghidra.trace.database.map.*;
|
||||||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData;
|
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData;
|
||||||
|
@ -426,6 +427,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
||||||
protected final ReadWriteLock lock;
|
protected final ReadWriteLock lock;
|
||||||
protected final DBTraceThreadManager threadManager;
|
protected final DBTraceThreadManager threadManager;
|
||||||
protected final DBTraceDataTypeManager dataTypeManager;
|
protected final DBTraceDataTypeManager dataTypeManager;
|
||||||
|
protected final DBTraceOverlaySpaceAdapter overlayAdapter;
|
||||||
|
|
||||||
protected final DBTraceAddressSnapRangePropertyMap<Long, DBTraceSymbolIDEntry> idMap;
|
protected final DBTraceAddressSnapRangePropertyMap<Long, DBTraceSymbolIDEntry> idMap;
|
||||||
|
|
||||||
|
@ -473,12 +475,14 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
||||||
|
|
||||||
public DBTraceSymbolManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock,
|
public DBTraceSymbolManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock,
|
||||||
TaskMonitor monitor, Language baseLanguage, DBTrace trace,
|
TaskMonitor monitor, Language baseLanguage, DBTrace trace,
|
||||||
DBTraceThreadManager threadManager, DBTraceDataTypeManager dataTypeManager)
|
DBTraceThreadManager threadManager, DBTraceDataTypeManager dataTypeManager,
|
||||||
|
DBTraceOverlaySpaceAdapter overlayAdapter)
|
||||||
throws VersionException, IOException {
|
throws VersionException, IOException {
|
||||||
this.trace = trace;
|
this.trace = trace;
|
||||||
this.lock = lock;
|
this.lock = lock;
|
||||||
this.threadManager = threadManager;
|
this.threadManager = threadManager;
|
||||||
this.dataTypeManager = dataTypeManager;
|
this.dataTypeManager = dataTypeManager;
|
||||||
|
this.overlayAdapter = overlayAdapter;
|
||||||
|
|
||||||
DBCachedObjectStoreFactory factory = trace.getStoreFactory();
|
DBCachedObjectStoreFactory factory = trace.getStoreFactory();
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ import ghidra.program.model.address.AddressSpace;
|
||||||
import ghidra.trace.model.TraceAddressSnapRange;
|
import ghidra.trace.model.TraceAddressSnapRange;
|
||||||
import ghidra.trace.model.stack.TraceStackFrame;
|
import ghidra.trace.model.stack.TraceStackFrame;
|
||||||
import ghidra.trace.model.thread.TraceThread;
|
import ghidra.trace.model.thread.TraceThread;
|
||||||
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A store of memory observations over time in a trace
|
* 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 {
|
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
|
* Obtain a memory space bound to a particular address space
|
||||||
*
|
*
|
||||||
|
|
|
@ -76,40 +76,72 @@ public class ToyDBTraceBuilder implements AutoCloseable {
|
||||||
this.trace = new DBTrace(name, language.getDefaultCompilerSpec(), this);
|
this.trace = new DBTrace(name, language.getDefaultCompilerSpec(), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Address addr(long offset) {
|
public Address addr(AddressSpace space, long offset) {
|
||||||
return language.getDefaultSpace().getAddress(offset);
|
return space.getAddress(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Address data(long offset) {
|
public Address addr(Language lang, long offset) {
|
||||||
return language.getDefaultDataSpace().getAddress(offset);
|
return addr(lang.getDefaultSpace(), offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Address addr(long offset) {
|
||||||
|
return addr(language, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Address addr(TraceGuestLanguage lang, long offset) {
|
public Address addr(TraceGuestLanguage lang, long offset) {
|
||||||
return lang.getLanguage().getDefaultSpace().getAddress(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) {
|
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) {
|
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) {
|
public TraceAddressSnapRange srange(long snap, long start, long end) {
|
||||||
return new ImmutableTraceAddressSnapRange(addr(start), addr(end), snap, snap);
|
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) {
|
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) {
|
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) {
|
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) {
|
public AddressSetView set(AddressRange... ranges) {
|
||||||
|
|
|
@ -32,6 +32,7 @@ import ghidra.lifecycle.Unfinished;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
|
import ghidra.program.model.listing.CodeUnit;
|
||||||
import ghidra.program.model.listing.ContextChangeException;
|
import ghidra.program.model.listing.ContextChangeException;
|
||||||
import ghidra.program.model.mem.MemBuffer;
|
import ghidra.program.model.mem.MemBuffer;
|
||||||
import ghidra.program.model.scalar.Scalar;
|
import ghidra.program.model.scalar.Scalar;
|
||||||
|
@ -1823,6 +1824,23 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
|
||||||
assertEquals(4, data.getLength());
|
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 a context-sensitive language
|
||||||
// TODO: Test using delay-slotted instructions (DBTraceCodemanager#instructionMax)
|
// TODO: Test using delay-slotted instructions (DBTraceCodemanager#instructionMax)
|
||||||
// TODO: How are lifespans of delay-slotted instructions bound to thatof the jump?
|
// TODO: How are lifespans of delay-slotted instructions bound to thatof the jump?
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ import org.junit.*;
|
||||||
import com.google.common.collect.Range;
|
import com.google.common.collect.Range;
|
||||||
|
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.address.AddressSpace;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
|
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
|
||||||
import ghidra.trace.database.ToyDBTraceBuilder;
|
import ghidra.trace.database.ToyDBTraceBuilder;
|
||||||
|
@ -555,4 +556,58 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
|
||||||
|
|
||||||
assertEquals(3, manager.getReferenceCountFrom(0, b.addr(0x4000)));
|
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)));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,15 +97,17 @@ public class ProgramAddressFactory extends DefaultAddressFactory {
|
||||||
return originalFactory;
|
return originalFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addOverlayAddressSpace(OverlayAddressSpace ovSpace) throws DuplicateNameException {
|
protected void addOverlayAddressSpace(OverlayAddressSpace ovSpace)
|
||||||
|
throws DuplicateNameException {
|
||||||
addAddressSpace(ovSpace);
|
addAddressSpace(ovSpace);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new OverlayAddressSpace based upon the given overlay blockName and base AddressSpace
|
* 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
|
* @param name the preferred name of the overlay address space to be created. This name may be
|
||||||
* name and avoid duplication.
|
* 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
|
* @param preserveName if true specified name will be preserved, if false an unique acceptable
|
||||||
* overlay space name will be generated from the specified name.
|
* overlay space name will be generated from the specified name.
|
||||||
* @param originalSpace the base AddressSpace to overlay
|
* @param originalSpace the base AddressSpace to overlay
|
||||||
|
@ -115,7 +117,7 @@ public class ProgramAddressFactory extends DefaultAddressFactory {
|
||||||
* @throws IllegalArgumentException if originalSpace is not permitted or preserveName is true
|
* @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) {
|
AddressSpace originalSpace, long minOffset, long maxOffset) {
|
||||||
|
|
||||||
if (!originalSpace.isMemorySpace() || originalSpace.isOverlaySpace()) {
|
if (!originalSpace.isMemorySpace() || originalSpace.isOverlaySpace()) {
|
||||||
|
@ -154,8 +156,8 @@ public class ProgramAddressFactory extends DefaultAddressFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a unique address space name based on the specified
|
* Get a unique address space name based on the specified baseOverlayName
|
||||||
* baseOverlayName
|
*
|
||||||
* @param baseOverlayName base overlay address space name
|
* @param baseOverlayName base overlay address space name
|
||||||
* @return unique overlay 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
|
* Get base overlay name removing any numeric suffix which may have been added to avoid
|
||||||
* have been added to avoid duplication. This method is intended
|
* duplication. This method is intended to be used during rename only.
|
||||||
* to be used during rename only.
|
*
|
||||||
* @param overlayName existing overlay space name
|
* @param overlayName existing overlay space name
|
||||||
* @return base overlay name with any trailing index removed
|
* @return base overlay name with any trailing index removed which may have been added to avoid
|
||||||
* which may have been added to avoid duplication.
|
* duplication.
|
||||||
*/
|
*/
|
||||||
private String getBaseOverlayName(String overlayName) {
|
private String getBaseOverlayName(String overlayName) {
|
||||||
int index = overlayName.lastIndexOf('.');
|
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
|
* Generate an allowed address space name from a block name. Use of unsupported characters will
|
||||||
* characters will be converted to underscore (includes colon and all whitespace chars).
|
* be converted to underscore (includes colon and all whitespace chars). double-underscore to
|
||||||
* double-underscore to ensure uniqueness.
|
* ensure uniqueness.
|
||||||
|
*
|
||||||
* @param blockName corresponding memory block name
|
* @param blockName corresponding memory block name
|
||||||
* @return overlay space name
|
* @return overlay space name
|
||||||
*/
|
*/
|
||||||
|
@ -249,18 +252,17 @@ public class ProgramAddressFactory extends DefaultAddressFactory {
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeOverlaySpace(String name) {
|
protected void removeOverlaySpace(String name) {
|
||||||
removeAddressSpace(name);
|
removeAddressSpace(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rename overlay with preferred newName. Actual name used will be returned
|
* Rename overlay with preferred newName. Actual name used will be returned and may differ from
|
||||||
* and may differ from specified newName to ensure validity and avoid
|
* specified newName to ensure validity and avoid duplication.
|
||||||
* duplication.
|
*
|
||||||
* @param oldOverlaySpaceName the existing overlay address space name
|
* @param oldOverlaySpaceName the existing overlay address space name
|
||||||
* @param newName the preferred new name of the overlay address space.
|
* @param newName the preferred new name of the overlay address space. This name may be modified
|
||||||
* This name may be modified to produce a valid overlay space
|
* to produce a valid overlay space name to avoid duplication.
|
||||||
* name to avoid duplication.
|
|
||||||
* @return new name applied to existing overlay space
|
* @return new name applied to existing overlay space
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -66,9 +66,10 @@ public class OverlayAddressSpace extends AbstractAddressSpace {
|
||||||
int lastColonPos = addrString.lastIndexOf(":");
|
int lastColonPos = addrString.lastIndexOf(":");
|
||||||
|
|
||||||
if (firstColonPos != lastColonPos) {
|
if (firstColonPos != lastColonPos) {
|
||||||
String middleName = addrString.substring(firstColonPos+1, lastColonPos);
|
String middleName = addrString.substring(firstColonPos + 1, lastColonPos);
|
||||||
if (middleName.equals(originalSpace.getName())) {
|
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 super.getAddress(addrString);
|
||||||
|
@ -106,7 +107,7 @@ public class OverlayAddressSpace extends AbstractAddressSpace {
|
||||||
throw new IllegalArgumentException("Address are in different spaces " +
|
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 {
|
// public Address subtractNoWrap(Address addr, long displacement) throws AddressOverflowException {
|
||||||
|
@ -139,12 +140,14 @@ public class OverlayAddressSpace extends AbstractAddressSpace {
|
||||||
public long getMinOffset() {
|
public long getMinOffset() {
|
||||||
return minOffset;
|
return minOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getMaxOffset() {
|
public long getMaxOffset() {
|
||||||
return maxOffset;
|
return maxOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean contains(long offset) {
|
public boolean contains(long offset) {
|
||||||
return (offset >= minOffset && offset <= maxOffset);
|
return Long.compareUnsigned(minOffset, offset) <= 0 &&
|
||||||
|
Long.compareUnsigned(offset, maxOffset) <= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -167,8 +170,7 @@ public class OverlayAddressSpace extends AbstractAddressSpace {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address getOverlayAddress(Address addr) {
|
public Address getOverlayAddress(Address addr) {
|
||||||
if (getOverlayedSpace().equals(addr.getAddressSpace()))
|
if (getOverlayedSpace().equals(addr.getAddressSpace())) {
|
||||||
{
|
|
||||||
if (contains(addr.getOffset())) {
|
if (contains(addr.getOffset())) {
|
||||||
return new GenericAddress(this, addr.getOffset());
|
return new GenericAddress(this, addr.getOffset());
|
||||||
}
|
}
|
||||||
|
@ -178,8 +180,9 @@ public class OverlayAddressSpace extends AbstractAddressSpace {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the given address is outside the overlay block, then the address is tranlated to an
|
* 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
|
* address in the base space with the same offset, otherwise (if the address exists in the
|
||||||
* block), it is returned
|
* overlay block), it is returned
|
||||||
|
*
|
||||||
* @param addr the address to translate to the base space if it is outside the overlay block
|
* @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
|
* @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.
|
||||||
|
@ -187,14 +190,15 @@ public class OverlayAddressSpace extends AbstractAddressSpace {
|
||||||
public Address translateAddress(Address addr) {
|
public Address translateAddress(Address addr) {
|
||||||
return translateAddress(addr, false);
|
return translateAddress(addr, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tranlated an overlay-space address (addr, which may exceed the bounds of the overlay space)
|
* 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.
|
* to an address in the base space with the same offset. If forceTranslation is false and addr
|
||||||
* If forceTranslation is false and addr is contained within the overlay-space
|
* is contained within the overlay-space the original addr is returned.
|
||||||
* the original addr is returned.
|
*
|
||||||
* @param addr the address to translate to the base space
|
* @param addr the address to translate to the base space
|
||||||
* @param forceTranslation if true addr will be translated even if addr falls within the
|
* @param forceTranslation if true addr will be translated even if addr falls within the bounds
|
||||||
* bounds of this overlay-space.
|
* of this overlay-space.
|
||||||
* @return either the given address if it is contained in the overlay memory block or an address
|
* @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.
|
||||||
*/
|
*/
|
||||||
|
@ -217,8 +221,9 @@ public class OverlayAddressSpace extends AbstractAddressSpace {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return super.toString()+OV_SEPARATER;
|
return super.toString() + OV_SEPARATER;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setName(String newName) {
|
public void setName(String newName) {
|
||||||
name = newName;
|
name = newName;
|
||||||
}
|
}
|
||||||
|
@ -226,6 +231,7 @@ public class OverlayAddressSpace extends AbstractAddressSpace {
|
||||||
public void setDatabaseKey(long key) {
|
public void setDatabaseKey(long key) {
|
||||||
databaseKey = key;
|
databaseKey = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getDatabaseKey() {
|
public long getDatabaseKey() {
|
||||||
return databaseKey;
|
return databaseKey;
|
||||||
}
|
}
|
||||||
|
@ -241,7 +247,7 @@ public class OverlayAddressSpace extends AbstractAddressSpace {
|
||||||
if (!(obj instanceof OverlayAddressSpace)) {
|
if (!(obj instanceof OverlayAddressSpace)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
OverlayAddressSpace s = (OverlayAddressSpace)obj;
|
OverlayAddressSpace s = (OverlayAddressSpace) obj;
|
||||||
|
|
||||||
return originalSpace.equals(s.originalSpace) &&
|
return originalSpace.equals(s.originalSpace) &&
|
||||||
name.equals(s.name) &&
|
name.equals(s.name) &&
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue