From 67d52f4fccbcb871d4f9bb4654dacb46c6c47a2d Mon Sep 17 00:00:00 2001
From: Dan <46821332+nsadeveloper789@users.noreply.github.com>
Date: Fri, 17 Jun 2022 11:41:33 -0400
Subject: [PATCH] GP-1967: Fix auto-disassembly for object-based traces, incl.
framework support.
---
.../dbgmodel/model/impl/dbgmodel_schema.xml | 2 +-
.../Debugger/data/ExtensionPoint.manifest | 1 +
.../RefreshRegistersScript.java | 78 +++++
.../core/debug/gui/DebuggerResources.java | 19 ++
.../core/debug/gui/register/RegisterRow.java | 3 +-
.../AbstractDebuggerPlatformMapper.java | 95 ++++++
.../AbstractDebuggerPlatformOffer.java} | 27 +-
.../AbstractDebuggerPlatformOpinion.java | 42 +++
.../debug/mapping/DebuggerMappingOpinion.java | 2 +-
.../debug/mapping/DebuggerPlatformMapper.java | 58 ++++
.../debug/mapping/DebuggerPlatformOffer.java | 99 ++++++
.../mapping/DebuggerPlatformOpinion.java | 158 ++++++++++
.../DefaultDebuggerPlatformMapper.java | 90 ++++++
.../core/debug/mapping/DisassemblyResult.java | 49 +++
.../legacy/LegacyDebuggerPlatformOpinion.java | 100 ++++++
.../platform/arm/ArmDisassemblyInject.java | 28 +-
.../dbgeng/DbgengDebuggerPlatformOpinion.java | 83 +++++
.../dbgeng/DbgengX64DisassemblyInject.java | 37 ++-
.../FridaArmDebuggerMappingOpinion.java | 2 +-
.../frida/FridaDebuggerPlatformOpinion.java | 134 ++++++++
.../GdbArmDebuggerMappingOpinion.java | 3 +-
.../gdb/GdbDebuggerPlatformOpinion.java | 99 ++++++
.../JdiDalvikDebuggerMappingOpinion.java | 2 +-
.../jdi/JdiDebuggerPlatformOpinion.java | 90 ++++++
.../JdiJvmDebuggerMappingOpinion.java} | 4 +-
.../LldbArmDebuggerMappingOpinion.java | 2 +-
.../lldb/LldbDebuggerPlatformOpinion.java | 134 ++++++++
.../AbstractDebuggerProgramLaunchOffer.java | 3 +
.../record/EmptyDebuggerRegisterMapper.java | 2 +-
.../DebuggerPlatformServicePlugin.java | 139 ++++++++
.../workflow/DisassembleAtPcDebuggerBot.java | 130 +++++---
.../DisassembleGuestTraceCommand.java | 59 ++++
.../workflow/DisassembleTraceCommand.java | 94 ++++++
.../debug/workflow/DisassemblyInject.java | 17 +-
.../app/services/DebuggerPlatformService.java | 74 +++++
.../core/debug/gui/DebuggerManualTest.java | 9 +-
.../mapping/TestDebuggerPlatformOpinion.java | 62 ++++
.../GdbArmDebuggerMappingOpinionTest.java | 6 +-
.../DisassembleAtPcDebuggerBotTest.java | 168 ++++++++++
.../java/ghidra/trace/database/DBTrace.java | 22 +-
.../ghidra/trace/database/DBTraceUtils.java | 38 +++
.../DBTraceRegisterContextManager.java | 6 +-
.../context/DBTraceRegisterContextSpace.java | 12 +-
.../DBTraceGuestPlatform.java} | 183 +++++++----
.../DBTraceGuestPlatformMappedMemory.java} | 18 +-
.../DBTraceGuestPlatformMappedRange.java} | 46 +--
.../guest/DBTracePlatformManager.java | 298 ++++++++++++++++++
.../language/DBTraceLanguageManager.java | 204 ------------
.../listing/AbstractDBTraceDataComponent.java | 6 +
.../database/listing/DBTraceCodeManager.java | 98 +++---
.../database/listing/DBTraceCodeSpace.java | 10 +-
.../trace/database/listing/DBTraceData.java | 44 +--
.../listing/DBTraceDefinedDataView.java | 3 +-
.../database/listing/DBTraceInstruction.java | 57 ++--
.../DBTraceInstructionsMemoryView.java | 20 +-
.../listing/DBTraceInstructionsView.java | 72 +++--
.../listing/UndefinedDBTraceData.java | 6 +
.../AbstractDBTraceProgramViewListing.java | 16 +-
.../database/stack/DBTraceObjectStack.java | 10 +-
.../stack/DBTraceObjectStackFrame.java | 2 +-
.../trace/database/target/DBTraceObject.java | 113 +++++--
.../InternalOrderedSuccessorsVisitor.java | 2 +-
.../InternalSuccessorsRelativeVisitor.java | 4 +-
.../main/java/ghidra/trace/model/Trace.java | 4 +-
.../trace/model/guest/TraceGuestPlatform.java | 132 ++++++++
.../TraceGuestPlatformMappedRange.java} | 9 +-
.../model/guest/TracePlatformManager.java | 74 +++++
.../model/language/TraceGuestLanguage.java | 71 -----
.../trace/model/listing/TraceCodeUnit.java | 8 +
.../model/listing/TraceInstructionsView.java | 34 +-
.../trace/util/DefaultTraceTimeViewport.java | 6 +-
.../trace/database/ToyDBTraceBuilder.java | 32 +-
.../DBTracePlatformManagerTest.java} | 213 +++++++------
.../listing/DBTraceCodeManagerTest.java | 90 +++---
.../database/listing/DBTraceCodeUnitTest.java | 76 ++---
.../DBTraceDisassemblerIntegrationTest.java | 16 +-
.../DBTraceProgramViewListingTest.java | 52 +--
.../framework/cmd/TypedBackgroundCommand.java | 42 +++
.../java/docking/DockingWindowManager.java | 3 +-
Ghidra/Processors/Toy/certification.manifest | 1 +
.../Processors/Toy/data/languages/toy.ldefs | 1 +
.../Toy/data/languages/toy64-long8.cspec | 90 ++++++
.../Processors/x86/data/languages/x86.ldefs | 1 +
83 files changed, 3561 insertions(+), 888 deletions(-)
create mode 100644 Ghidra/Debug/Debugger/ghidra_scripts/RefreshRegistersScript.java
create mode 100644 Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/AbstractDebuggerPlatformMapper.java
rename Ghidra/Debug/{Framework-TraceModeling/src/main/java/ghidra/trace/model/language/TraceLanguageManager.java => Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/AbstractDebuggerPlatformOffer.java} (52%)
create mode 100644 Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/AbstractDebuggerPlatformOpinion.java
create mode 100644 Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DebuggerPlatformMapper.java
create mode 100644 Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DebuggerPlatformOffer.java
create mode 100644 Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DebuggerPlatformOpinion.java
create mode 100644 Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DefaultDebuggerPlatformMapper.java
create mode 100644 Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DisassemblyResult.java
create mode 100644 Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/legacy/LegacyDebuggerPlatformOpinion.java
create mode 100644 Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/dbgeng/DbgengDebuggerPlatformOpinion.java
rename Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/{arm => frida}/FridaArmDebuggerMappingOpinion.java (97%)
create mode 100644 Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/frida/FridaDebuggerPlatformOpinion.java
rename Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/{arm => gdb}/GdbArmDebuggerMappingOpinion.java (95%)
create mode 100644 Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/gdb/GdbDebuggerPlatformOpinion.java
rename Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/{jvm => jdi}/JdiDalvikDebuggerMappingOpinion.java (98%)
create mode 100644 Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/jdi/JdiDebuggerPlatformOpinion.java
rename Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/{jvm/JdiJavaDebuggerMappingOpinion.java => jdi/JdiJvmDebuggerMappingOpinion.java} (95%)
rename Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/{arm => lldb}/LldbArmDebuggerMappingOpinion.java (98%)
create mode 100644 Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/lldb/LldbDebuggerPlatformOpinion.java
create mode 100644 Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/platform/DebuggerPlatformServicePlugin.java
create mode 100644 Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/workflow/DisassembleGuestTraceCommand.java
create mode 100644 Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/workflow/DisassembleTraceCommand.java
create mode 100644 Ghidra/Debug/Debugger/src/main/java/ghidra/app/services/DebuggerPlatformService.java
create mode 100644 Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/mapping/TestDebuggerPlatformOpinion.java
rename Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/platform/{arm => gdb}/GdbArmDebuggerMappingOpinionTest.java (95%)
create mode 100644 Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/workflow/DisassembleAtPcDebuggerBotTest.java
rename Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/{language/DBTraceGuestLanguage.java => guest/DBTraceGuestPlatform.java} (54%)
rename Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/{language/DBTraceGuestLanguageMappedMemory.java => guest/DBTraceGuestPlatformMappedMemory.java} (96%)
rename Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/{language/DBTraceGuestLanguageMappedRange.java => guest/DBTraceGuestPlatformMappedRange.java} (80%)
create mode 100644 Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTracePlatformManager.java
delete mode 100644 Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/language/DBTraceLanguageManager.java
create mode 100644 Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/guest/TraceGuestPlatform.java
rename Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/{language/TraceGuestLanguageMappedRange.java => guest/TraceGuestPlatformMappedRange.java} (83%)
create mode 100644 Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/guest/TracePlatformManager.java
delete mode 100644 Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/language/TraceGuestLanguage.java
rename Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/{language/DBTraceLanguageManagerTest.java => guest/DBTracePlatformManagerTest.java} (58%)
create mode 100644 Ghidra/Debug/ProposedUtils/src/main/java/ghidra/framework/cmd/TypedBackgroundCommand.java
create mode 100644 Ghidra/Processors/Toy/data/languages/toy64-long8.cspec
diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/resources/agent/dbgmodel/model/impl/dbgmodel_schema.xml b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/resources/agent/dbgmodel/model/impl/dbgmodel_schema.xml
index 8ca99de662..bbc3117a29 100644
--- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/resources/agent/dbgmodel/model/impl/dbgmodel_schema.xml
+++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/resources/agent/dbgmodel/model/impl/dbgmodel_schema.xml
@@ -222,7 +222,7 @@
-
+
diff --git a/Ghidra/Debug/Debugger/data/ExtensionPoint.manifest b/Ghidra/Debug/Debugger/data/ExtensionPoint.manifest
index bcbfbe4845..8a0ed8a9a0 100644
--- a/Ghidra/Debug/Debugger/data/ExtensionPoint.manifest
+++ b/Ghidra/Debug/Debugger/data/ExtensionPoint.manifest
@@ -2,6 +2,7 @@ AutoReadMemorySpec
DebuggerBot
DebuggerMappingOpinion
DebuggerModelFactory
+DebuggerPlatformOpinion
DebuggerProgramLaunchOpinion
DisassemblyInject
LocationTrackingSpec
diff --git a/Ghidra/Debug/Debugger/ghidra_scripts/RefreshRegistersScript.java b/Ghidra/Debug/Debugger/ghidra_scripts/RefreshRegistersScript.java
new file mode 100644
index 0000000000..18234e2400
--- /dev/null
+++ b/Ghidra/Debug/Debugger/ghidra_scripts/RefreshRegistersScript.java
@@ -0,0 +1,78 @@
+/* ###
+ * 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.
+ */
+import ghidra.app.plugin.core.debug.DebuggerCoordinates;
+import ghidra.app.script.GhidraScript;
+import ghidra.app.services.*;
+import ghidra.dbg.DebuggerObjectModel;
+import ghidra.dbg.target.TargetObject;
+import ghidra.dbg.target.TargetRegisterBank;
+import ghidra.dbg.util.PathMatcher;
+
+public class RefreshRegistersScript extends GhidraScript {
+ @Override
+ protected void run() throws Exception {
+ // There is no need to fish this from the ObjectUpdateService, you can get it directly
+ DebuggerModelService modelService = state.getTool().getService(DebuggerModelService.class);
+ // The current model is retrieved with one method, no need to stream or filter
+ DebuggerObjectModel model = modelService.getCurrentModel();
+
+ /**
+ * Navigating a model generically requires some introspection. Use the schema. We used to
+ * decouple the descriptions (RegisterContainer) from the values (RegisterBank), but we
+ * always realize the two interfaces on the same no it seems. Still, we need to work with
+ * values, so we search for all the Banks.
+ */
+ PathMatcher allBanksMatcher =
+ model.getRootSchema().searchFor(TargetRegisterBank.class, true);
+ for (TargetObject objBank : allBanksMatcher.fetchSuccessors(model.fetchModelRoot().get())
+ .get()
+ .values()) {
+ // Because of a bug in our path search, this type check is still necessary :(
+ if (!(objBank instanceof TargetRegisterBank)) {
+ continue;
+ }
+ TargetRegisterBank bank = (TargetRegisterBank) objBank;
+ // This is equivalent to hitting the "Flush Caches" button in the Target Provider
+ bank.invalidateCaches().get();
+ // If you know the names of the registers to read
+ bank.readRegistersNamed("rax", "rbx").get();
+ // Values are coupled to elements, so we can also just refresh them to re-read all
+ bank.fetchElements(true).get();
+ }
+
+ /**
+ * Alternatively, to refresh just the bank for the current thread or frame, we need to
+ * determine the active frame. We'll do that by asking the TraceManagerService. Then,
+ * because that's in "trace land," we'll use the TraceRecorder to map that into "target
+ * land." Generally, you'd then need to navigate the schema as before, but relative to the
+ * target object. Because fetching registers is so common, this is already built in to the
+ * recorder.
+ */
+ DebuggerTraceManagerService traceManager =
+ state.getTool().getService(DebuggerTraceManagerService.class);
+ // There are also getCurreentTrace(), etc., if you want just the one thing
+ DebuggerCoordinates current = traceManager.getCurrent();
+
+ // Now, we need to get the relevant recorder
+ TraceRecorder recorder = modelService.getRecorder(current.getTrace());
+ // There's a chance of an NPE here if there is no "current frame"
+ TargetRegisterBank bank =
+ recorder.getTargetRegisterBank(current.getThread(), current.getFrame());
+ // Now do the same to the bank as before
+ bank.invalidateCaches().get();
+ bank.fetchElements(true).get();
+ }
+}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerResources.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerResources.java
index 5f834dc155..1b288160a9 100644
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerResources.java
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerResources.java
@@ -76,6 +76,7 @@ public interface DebuggerResources {
ImageIcon ICON_TRACE = Trace.TRACE_ICON;
ImageIcon ICON_THREAD = ResourceManager.loadImage("images/thread.png");
ImageIcon ICON_PROGRAM = ProgramContentHandler.PROGRAM_ICON;
+ ImageIcon ICON_PROCESSOR = ResourceManager.loadImage("images/kcmprocessor.png");
ImageIcon ICON_LAUNCH = ResourceManager.loadImage("images/launch.png");
ImageIcon ICON_ATTACH = ResourceManager.loadImage("images/attach.png");
@@ -795,6 +796,24 @@ public interface DebuggerResources {
}
}
+ interface ChoosePlatformAction {
+ String NAME = "Choose Platform";
+ String GROUP = GROUP_MAPPING;
+ String DESCRIPTION = "Manually select the target platform";
+ Icon ICON = ICON_PROCESSOR;
+ String HELP_ANCHOR = "choose_platform";
+
+ public static ActionBuilder builder(Plugin owner) {
+ String ownerName = owner.getName();
+ return new ActionBuilder(ownerName, NAME)
+ .description(DESCRIPTION)
+ .menuPath(DebuggerPluginPackage.NAME, NAME)
+ .menuGroup(GROUP)
+ .menuIcon(ICON)
+ .helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
+ }
+ }
+
abstract class AbstractRecordAction extends DockingAction {
public static final String NAME = "Record";
public static final Icon ICON = ICON_TRACE;
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/RegisterRow.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/RegisterRow.java
index 8844502dbb..e2ee378a3a 100644
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/RegisterRow.java
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/RegisterRow.java
@@ -16,6 +16,7 @@
package ghidra.app.plugin.core.debug.gui.register;
import java.math.BigInteger;
+import java.util.Objects;
import ghidra.program.model.data.DataType;
import ghidra.program.model.lang.Language;
@@ -31,7 +32,7 @@ public class RegisterRow {
public RegisterRow(DebuggerRegistersProvider provider, int number, Register register) {
this.provider = provider;
this.number = number;
- this.register = register;
+ this.register = Objects.requireNonNull(register);
this.favorite = provider.isFavorite(register);
}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/AbstractDebuggerPlatformMapper.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/AbstractDebuggerPlatformMapper.java
new file mode 100644
index 0000000000..aaddc4fe64
--- /dev/null
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/AbstractDebuggerPlatformMapper.java
@@ -0,0 +1,95 @@
+/* ###
+ * 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.app.plugin.core.debug.mapping;
+
+import java.util.Collection;
+import java.util.Set;
+
+import ghidra.app.plugin.core.debug.workflow.DisassembleTraceCommand;
+import ghidra.app.plugin.core.debug.workflow.DisassemblyInject;
+import ghidra.framework.plugintool.PluginTool;
+import ghidra.program.model.address.*;
+import ghidra.program.model.lang.*;
+import ghidra.trace.model.Trace;
+import ghidra.trace.model.guest.TraceGuestPlatform;
+import ghidra.trace.model.target.TraceObject;
+import ghidra.trace.model.thread.TraceThread;
+import ghidra.util.task.TaskMonitor;
+
+public abstract class AbstractDebuggerPlatformMapper implements DebuggerPlatformMapper {
+ protected final PluginTool tool;
+ protected final Trace trace;
+
+ public AbstractDebuggerPlatformMapper(PluginTool tool, Trace trace) {
+ this.tool = tool;
+ this.trace = trace;
+ }
+
+ protected boolean canInterpret(TraceObject newFocus, long snap, TraceObject env,
+ String debugger, String arch, String os, Endian endian) {
+ return true;
+ }
+
+ @Override
+ public boolean canInterpret(TraceObject newFocus, long snap) {
+ TraceObject env = DebuggerPlatformOpinion.getEnvironment(newFocus, snap);
+ if (env == null) {
+ return canInterpret(newFocus, snap, env, null, null, null, null);
+ }
+ String debugger = DebuggerPlatformOpinion.getDebugggerFromEnv(env, snap);
+ String arch = DebuggerPlatformOpinion.getArchitectureFromEnv(env, snap);
+ String os = DebuggerPlatformOpinion.getOperatingSystemFromEnv(env, snap);
+ Endian endian = DebuggerPlatformOpinion.getEndianFromEnv(env, snap);
+ return canInterpret(newFocus, snap, env, debugger, arch, os, endian);
+ }
+
+ protected boolean isCancelSilently(Address start, long snap) {
+ return trace.getCodeManager().definedUnits().containsAddress(snap, start);
+ }
+
+ protected Collection getDisassemblyInjections(TraceObject object) {
+ return Set.of();
+ }
+
+ protected abstract CompilerSpec getCompilerSpec(TraceObject object);
+
+ @Override
+ public DisassemblyResult disassemble(TraceThread thread, TraceObject object,
+ Address start, AddressSetView restricted, long snap, TaskMonitor monitor) {
+ if (isCancelSilently(start, snap)) {
+ return DisassemblyResult.CANCELLED;
+ }
+ TraceGuestPlatform guest =
+ trace.getPlatformManager().getGuestPlatform(getCompilerSpec(object));
+
+ Collection injects = getDisassemblyInjections(object);
+ DisassembleTraceCommand dis =
+ DisassembleTraceCommand.create(guest, start, restricted);
+ Language language = guest == null ? trace.getBaseLanguage() : guest.getLanguage();
+ AddressSet startSet = new AddressSet(start);
+ for (DisassemblyInject i : injects) {
+ i.pre(tool, dis, trace, language, snap, null, startSet, restricted);
+ }
+ boolean result = dis.applyToTyped(trace.getFixedProgramView(snap), monitor);
+ if (!result) {
+ return DisassemblyResult.failed(dis.getStatusMsg());
+ }
+ for (DisassemblyInject i : injects) {
+ i.post(tool, trace, snap, dis.getDisassembledAddressSet());
+ }
+ return DisassemblyResult.success(!dis.getDisassembledAddressSet().isEmpty());
+ }
+}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/language/TraceLanguageManager.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/AbstractDebuggerPlatformOffer.java
similarity index 52%
rename from Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/language/TraceLanguageManager.java
rename to Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/AbstractDebuggerPlatformOffer.java
index bf8f1c15db..0e190f1514 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/language/TraceLanguageManager.java
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/AbstractDebuggerPlatformOffer.java
@@ -13,19 +13,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.trace.model.language;
+package ghidra.app.plugin.core.debug.mapping;
-import java.util.Collection;
+import ghidra.program.model.lang.CompilerSpec;
-import ghidra.program.model.lang.InstructionSet;
-import ghidra.program.model.lang.Language;
+public abstract class AbstractDebuggerPlatformOffer implements DebuggerPlatformOffer {
+ private final String description;
+ protected final CompilerSpec cSpec;
-public interface TraceLanguageManager {
- Language getBaseLanguage();
+ public AbstractDebuggerPlatformOffer(String description, CompilerSpec cSpec) {
+ this.description = description;
+ this.cSpec = cSpec;
+ }
- TraceGuestLanguage addGuestLanguage(Language language);
+ @Override
+ public String getDescription() {
+ return description;
+ }
- Collection getGuestLanguages();
-
- InstructionSet mapGuestInstructionAddressesToHost(InstructionSet instructionSet);
+ @Override
+ public CompilerSpec getCompilerSpec() {
+ return cSpec;
+ }
}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/AbstractDebuggerPlatformOpinion.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/AbstractDebuggerPlatformOpinion.java
new file mode 100644
index 0000000000..6a9234f164
--- /dev/null
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/AbstractDebuggerPlatformOpinion.java
@@ -0,0 +1,42 @@
+/* ###
+ * 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.app.plugin.core.debug.mapping;
+
+import java.util.Set;
+
+import ghidra.program.model.lang.Endian;
+import ghidra.trace.model.Trace;
+import ghidra.trace.model.target.TraceObject;
+
+public abstract class AbstractDebuggerPlatformOpinion implements DebuggerPlatformOpinion {
+
+ protected abstract Set getOffers(TraceObject object, long snap,
+ TraceObject env, String debugger, String arch, String os, Endian endian);
+
+ @Override
+ public Set getOffers(Trace trace, TraceObject object, long snap,
+ boolean includeOverrides) {
+ TraceObject env = DebuggerPlatformOpinion.getEnvironment(object, snap);
+ if (env == null) {
+ return getOffers(object, snap, env, null, null, null, null);
+ }
+ String debugger = DebuggerPlatformOpinion.getDebugggerFromEnv(env, snap);
+ String arch = DebuggerPlatformOpinion.getArchitectureFromEnv(env, snap);
+ String os = DebuggerPlatformOpinion.getOperatingSystemFromEnv(env, snap);
+ Endian endian = DebuggerPlatformOpinion.getEndianFromEnv(env, snap);
+ return getOffers(object, snap, env, debugger, arch, os, endian);
+ }
+}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DebuggerMappingOpinion.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DebuggerMappingOpinion.java
index 05bafefc0a..03d9da0bbd 100644
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DebuggerMappingOpinion.java
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DebuggerMappingOpinion.java
@@ -71,7 +71,7 @@ public interface DebuggerMappingOpinion extends ExtensionPoint {
*
* @param target the target to be recorded, usually a process
* @param includeOverrides true to include offers with negative confidence
- * @return a future which completes with the set of offers
+ * @return a list of offers ordered highest confidence first
*/
public static List queryOpinions(TargetObject target,
boolean includeOverrides) {
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DebuggerPlatformMapper.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DebuggerPlatformMapper.java
new file mode 100644
index 0000000000..ac7e7e551e
--- /dev/null
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DebuggerPlatformMapper.java
@@ -0,0 +1,58 @@
+/* ###
+ * 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.app.plugin.core.debug.mapping;
+
+import ghidra.program.model.address.Address;
+import ghidra.program.model.address.AddressSetView;
+import ghidra.trace.model.target.TraceObject;
+import ghidra.trace.model.thread.TraceThread;
+import ghidra.util.task.TaskMonitor;
+
+/**
+ * An object for interpreting a trace according to a chosen platform
+ */
+public interface DebuggerPlatformMapper {
+ /**
+ * Prepare the given trace for interpretation under this mapper
+ *
+ * @param trace the trace
+ * @param snap the snap
+ */
+ void addToTrace(long snap);
+
+ /**
+ * When focus changes, decide if this mapper should remain active
+ *
+ * @param newFocus the newly-focused object
+ * @param snap the snap, usually the current snap
+ * @return true to remain active, false to select a new mapper
+ */
+ boolean canInterpret(TraceObject newFocus, long snap);
+
+ /**
+ * Disassemble starting at a given address and snap, limited to a given address set
+ *
+ * @param thread the thread if applicable
+ * @param object the object for platform context
+ * @param start the starting address
+ * @param restricted the limit of disassembly
+ * @param snap the snap, usually the current snap
+ * @param monitor a monitor for the disassembler
+ * @return the result
+ */
+ DisassemblyResult disassemble(TraceThread thread, TraceObject object,
+ Address start, AddressSetView restricted, long snap, TaskMonitor monitor);
+}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DebuggerPlatformOffer.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DebuggerPlatformOffer.java
new file mode 100644
index 0000000000..714bb427b7
--- /dev/null
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DebuggerPlatformOffer.java
@@ -0,0 +1,99 @@
+/* ###
+ * 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.app.plugin.core.debug.mapping;
+
+import ghidra.framework.plugintool.PluginTool;
+import ghidra.program.model.lang.*;
+import ghidra.program.util.DefaultLanguageService;
+import ghidra.trace.model.Trace;
+
+/**
+ * An offer to map from a trace to a Ghidra langauge / compiler
+ */
+public interface DebuggerPlatformOffer {
+
+ /**
+ * Get a human-readable description of the offer.
+ *
+ *
+ * Generally, more detailed descriptions imply a higher confidence.
+ *
+ * @return the description
+ */
+ String getDescription();
+
+ /**
+ * Get the confidence of this offer.
+ *
+ *
+ * Offers with numerically higher confidence are preferred. Negative confidence values are
+ * considered "manual overrides," and so are never selected automatically and are hidden from
+ * prompts by default.
+ *
+ *
+ * TODO: Spec out some standard numbers. Maybe an enum?
+ *
+ * @return the confidence
+ */
+ int getConfidence();
+
+ /**
+ * Check if the confidence indicates this offer is a manual override.
+ *
+ * @return true if the confidence is negative
+ */
+ default boolean isOverride() {
+ return getConfidence() < 0;
+ }
+
+ /**
+ * Get the language to which this offer can map
+ *
+ * @return the langauge
+ */
+ default Language getLanguage() {
+ CompilerSpec cSpec = getCompilerSpec();
+ return cSpec == null ? null : cSpec.getLanguage();
+ }
+
+ /**
+ * Get the compiler to which this offer can map
+ *
+ * @return the compiler spec
+ */
+ CompilerSpec getCompilerSpec();
+
+ default CompilerSpec getCompilerSpec(LanguageID langID, CompilerSpecID cSpecID) {
+ try {
+ LanguageService langServ = DefaultLanguageService.getLanguageService();
+ Language lang = langServ.getLanguage(langID);
+ return cSpecID == null ? lang.getDefaultCompilerSpec()
+ : lang.getCompilerSpecByID(cSpecID);
+ }
+ catch (LanguageNotFoundException | CompilerSpecNotFoundException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ /**
+ * Get the mapper, which implements this offer
+ *
+ * @param tool the plugin tool
+ * @param trace the trace the trace to be mapped
+ * @return the mapper
+ */
+ DebuggerPlatformMapper take(PluginTool tool, Trace trace);
+}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DebuggerPlatformOpinion.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DebuggerPlatformOpinion.java
new file mode 100644
index 0000000000..b82654f117
--- /dev/null
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DebuggerPlatformOpinion.java
@@ -0,0 +1,158 @@
+/* ###
+ * 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.app.plugin.core.debug.mapping;
+
+import java.util.*;
+
+import com.google.common.collect.Range;
+
+import ghidra.dbg.target.TargetEnvironment;
+import ghidra.dbg.util.PathPredicates;
+import ghidra.program.model.lang.Endian;
+import ghidra.trace.model.Trace;
+import ghidra.trace.model.target.TraceObject;
+import ghidra.trace.model.target.TraceObjectValue;
+import ghidra.util.Msg;
+import ghidra.util.classfinder.ClassSearcher;
+import ghidra.util.classfinder.ExtensionPoint;
+
+/**
+ * An opinion governing analysis and display of a trace according to a platform (processor, ISA, OS,
+ * ABI, etc.)
+ *
+ *
+ * This is meant for "object-based" traces, which may soon supplant "table-based" traces. The latter
+ * requires mapping between the target model and the trace, and so the UI need not worry about
+ * normalizing; however, without a mapping, nothing works. The former allows for direct recording of
+ * the model into the trace without prior mapping. Instead, the choice of platform and
+ * interpretation is performed by the front-end analysis and display. These are essentially the
+ * counterpart to {@link DebuggerMappingOpinion}.
+ *
+ *
+ * The opinions are queried, each of which may produce zero or more scored offers. Depending on
+ * context and automation, the top offer may be chosen automatically, or the user may be prompted to
+ * select from a sorted list. The chosen offer is then applied. Application here means writing
+ * metadata to the trace database, usually as "guest platforms." The analysis and display use that
+ * metadata to interpret the trace data, e.g., to select a language when disassembling at the
+ * program counter.
+ */
+public interface DebuggerPlatformOpinion extends ExtensionPoint {
+
+ Comparator HIGHEST_CONFIDENCE_FIRST =
+ Comparator.comparing(o -> -o.getConfidence());
+
+ /**
+ * Find the environment for the given object
+ *
+ * @param object the object, usually the user's focus
+ * @param snap the current snap
+ * @return the environment object, or null
+ */
+ static TraceObject getEnvironment(TraceObject object, long snap) {
+ if (object == null) {
+ return null;
+ }
+ TraceObject root = object.getRoot();
+ List pathToEnv = root.getTargetSchema()
+ .searchForSuitable(TargetEnvironment.class, object.getCanonicalPath().getKeyList());
+ if (pathToEnv == null) {
+ return null;
+ }
+ return root.getSuccessors(Range.singleton(snap), PathPredicates.pattern(pathToEnv))
+ .findAny()
+ .map(p -> p.getDestination(root))
+ .orElse(null);
+ }
+
+ static String getStringAttribute(TraceObject obj, long snap, String key) {
+ TraceObjectValue val = obj.getValue(snap, key);
+ if (val == null) {
+ return null;
+ }
+ return val.getValue().toString();
+ }
+
+ static String getDebugggerFromEnv(TraceObject env, long snap) {
+ return getStringAttribute(env, snap, TargetEnvironment.DEBUGGER_ATTRIBUTE_NAME);
+ }
+
+ static String getArchitectureFromEnv(TraceObject env, long snap) {
+ return getStringAttribute(env, snap, TargetEnvironment.ARCH_ATTRIBUTE_NAME);
+ }
+
+ static String getOperatingSystemFromEnv(TraceObject env, long snap) {
+ return getStringAttribute(env, snap, TargetEnvironment.OS_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Get the endianness from the given environment
+ *
+ * @param env the environment object
+ * @param snap the current snap
+ * @return the endianness, or null
+ */
+ static Endian getEndianFromEnv(TraceObject env, long snap) {
+ String strEndian = getStringAttribute(env, snap, TargetEnvironment.ENDIAN_ATTRIBUTE_NAME);
+ if (strEndian == null) {
+ return null;
+ }
+ if (strEndian.toLowerCase().contains("little")) {
+ return Endian.LITTLE;
+ }
+ if (strEndian.toLowerCase().contains("big")) {
+ return Endian.BIG;
+ }
+ return null;
+ }
+
+ /**
+ * Query all known opinions for offers of platform interpretation
+ *
+ * @param trace the trace
+ * @param object the object, usually the one in focus
+ * @param snap the snap
+ * @param includeOverrides true to include offers with negative confidence
+ * @return the list of offers ordered highest confidence first
+ */
+ static List queryOpinions(Trace trace, TraceObject object, long snap,
+ boolean includeOverrides) {
+ List result = new ArrayList<>();
+ for (DebuggerPlatformOpinion opinion : ClassSearcher
+ .getInstances(DebuggerPlatformOpinion.class)) {
+ try {
+ Set offers =
+ opinion.getOffers(trace, object, snap, includeOverrides);
+ result.addAll(offers);
+ }
+ catch (Exception e) {
+ Msg.error(DebuggerPlatformOpinion.class,
+ "Problem querying opinion " + opinion + " for platform offers: " + e);
+ }
+ }
+ result.sort(HIGHEST_CONFIDENCE_FIRST);
+ return result;
+ }
+
+ /**
+ * Render offers for the given object
+ *
+ * @param object the object, usually the one in focus
+ * @param includeOverrides true to include offers with negative confidence
+ * @return zero or more offers to interpret the target according to a platform
+ */
+ Set getOffers(Trace trace, TraceObject object, long snap,
+ boolean includeOverrides);
+}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DefaultDebuggerPlatformMapper.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DefaultDebuggerPlatformMapper.java
new file mode 100644
index 0000000000..fc14beb139
--- /dev/null
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DefaultDebuggerPlatformMapper.java
@@ -0,0 +1,90 @@
+/* ###
+ * 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.app.plugin.core.debug.mapping;
+
+import ghidra.framework.plugintool.PluginTool;
+import ghidra.program.model.address.*;
+import ghidra.program.model.lang.CompilerSpec;
+import ghidra.program.model.lang.Language;
+import ghidra.trace.model.Trace;
+import ghidra.trace.model.guest.TraceGuestPlatform;
+import ghidra.trace.model.guest.TracePlatformManager;
+import ghidra.trace.model.target.TraceObject;
+import ghidra.util.MathUtilities;
+
+public class DefaultDebuggerPlatformMapper extends AbstractDebuggerPlatformMapper {
+
+ protected static boolean isHarvard(Language language) {
+ return language.getDefaultSpace() != language.getDefaultDataSpace();
+ }
+
+ protected final PluginTool tool;
+ protected final CompilerSpec cSpec;
+
+ public DefaultDebuggerPlatformMapper(PluginTool tool, Trace trace, CompilerSpec cSpec) {
+ super(tool, trace);
+ validate(cSpec);
+ this.tool = tool;
+ this.cSpec = cSpec;
+ }
+
+ protected void validate(CompilerSpec cSpec) {
+ if (isHarvard(cSpec.getLanguage())) {
+ throw new IllegalArgumentException("This mapper cannot handle Harvard guests");
+ }
+ }
+
+ @Override
+ protected CompilerSpec getCompilerSpec(TraceObject object) {
+ return cSpec;
+ }
+
+ @Override
+ public void addToTrace(long snap) {
+ TracePlatformManager platformManager = trace.getPlatformManager();
+ TraceGuestPlatform platform = platformManager.getOrAddGuestPlatform(cSpec);
+ if (platform == null) {
+ return; // It's the host compiler spec
+ }
+ addMappedRanges(platform);
+ }
+
+ protected void addMappedRanges(TraceGuestPlatform platform) {
+ Trace trace = platform.getTrace();
+ AddressSpace hostSpace = trace.getBaseAddressFactory().getDefaultAddressSpace();
+ AddressSpace guestSpace = platform.getAddressFactory().getDefaultAddressSpace();
+ long min = MathUtilities.unsignedMax(hostSpace.getMinAddress().getOffset(),
+ guestSpace.getMinAddress().getOffset());
+ long max = MathUtilities.unsignedMin(hostSpace.getMaxAddress().getOffset(),
+ guestSpace.getMaxAddress().getOffset());
+ Address hostStart = hostSpace.getAddress(min);
+ Address guestStart = guestSpace.getAddress(min);
+
+ /*
+ * TODO: I could perhaps do better, but assuming I'm the only source of mappings, this
+ * should suffice.
+ */
+ if (platform.getHostAddressSet().contains(hostStart)) {
+ return;
+ }
+ try {
+ platform.addMappedRange(hostStart, guestStart, max - min + 1);
+ }
+ catch (AddressOverflowException e) {
+ throw new AssertionError(e);
+ }
+ }
+}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DisassemblyResult.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DisassemblyResult.java
new file mode 100644
index 0000000000..25364d9574
--- /dev/null
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DisassemblyResult.java
@@ -0,0 +1,49 @@
+/* ###
+ * 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.app.plugin.core.debug.mapping;
+
+public class DisassemblyResult {
+ public static final DisassemblyResult SUCCESS = new DisassemblyResult(true, null);
+ public static final DisassemblyResult CANCELLED = new DisassemblyResult(false, null);
+
+ public static DisassemblyResult failed(String errorMessage) {
+ return new DisassemblyResult(false, errorMessage);
+ }
+
+ public static DisassemblyResult success(boolean atLeastOne) {
+ return atLeastOne ? SUCCESS : CANCELLED;
+ }
+
+ private final boolean atLeastOne;
+ private final String errorMessage;
+
+ public DisassemblyResult(boolean atLeastOne, String errorMessage) {
+ this.atLeastOne = atLeastOne;
+ this.errorMessage = errorMessage;
+ }
+
+ public boolean isAtLeastOne() {
+ return atLeastOne;
+ }
+
+ public boolean isSuccess() {
+ return errorMessage == null;
+ }
+
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/legacy/LegacyDebuggerPlatformOpinion.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/legacy/LegacyDebuggerPlatformOpinion.java
new file mode 100644
index 0000000000..ce4834f6b4
--- /dev/null
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/legacy/LegacyDebuggerPlatformOpinion.java
@@ -0,0 +1,100 @@
+/* ###
+ * 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.app.plugin.core.debug.mapping.legacy;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+import ghidra.app.plugin.core.debug.mapping.*;
+import ghidra.app.plugin.core.debug.workflow.DisassemblyInject;
+import ghidra.framework.plugintool.PluginTool;
+import ghidra.lifecycle.Transitional;
+import ghidra.program.model.lang.CompilerSpec;
+import ghidra.trace.model.Trace;
+import ghidra.trace.model.target.TraceObject;
+import ghidra.util.classfinder.ClassSearcher;
+
+/**
+ * An opinion which retains the front-end functionality when using the mapped recorder, i.e., when
+ * displaying non-object-based traces.
+ */
+@Transitional
+public class LegacyDebuggerPlatformOpinion implements DebuggerPlatformOpinion {
+
+ protected static class LegacyDebuggerPlatformMapper extends AbstractDebuggerPlatformMapper {
+ public LegacyDebuggerPlatformMapper(PluginTool tool, Trace trace) {
+ super(tool, trace);
+ }
+
+ @Override
+ protected CompilerSpec getCompilerSpec(TraceObject object) {
+ return trace.getBaseCompilerSpec();
+ }
+
+ @Override
+ public void addToTrace(long snap) {
+ // Nothing to do
+ }
+
+ @Override
+ public boolean canInterpret(TraceObject newFocus, long snap) {
+ return true;
+ }
+
+ @Override
+ protected Collection getDisassemblyInjections(TraceObject object) {
+ // Track an injects set using a listener instead?
+ return ClassSearcher.getInstances(DisassemblyInject.class)
+ .stream()
+ .filter(i -> i.isApplicable(trace))
+ .sorted(Comparator.comparing(i -> i.getPriority()))
+ .collect(Collectors.toList());
+ }
+ }
+
+ enum Offers implements DebuggerPlatformOffer {
+ LEGACY {
+ @Override
+ public String getDescription() {
+ return "Legacy (Already mapped by recorder)";
+ }
+
+ @Override
+ public int getConfidence() {
+ return 1;
+ }
+
+ @Override
+ public CompilerSpec getCompilerSpec() {
+ return null;
+ }
+
+ @Override
+ public DebuggerPlatformMapper take(PluginTool tool, Trace trace) {
+ return new LegacyDebuggerPlatformMapper(tool, trace);
+ }
+ };
+ }
+
+ @Override
+ public Set getOffers(Trace trace, TraceObject focus, long snap,
+ boolean includeOverrides) {
+ if (trace.getObjectManager().getRootObject() != null) {
+ return Set.of();
+ }
+ return Set.of(Offers.LEGACY);
+ }
+}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/arm/ArmDisassemblyInject.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/arm/ArmDisassemblyInject.java
index 3adf2ff9e0..69eb316a22 100644
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/arm/ArmDisassemblyInject.java
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/arm/ArmDisassemblyInject.java
@@ -17,16 +17,13 @@ package ghidra.app.plugin.core.debug.platform.arm;
import java.math.BigInteger;
-import ghidra.app.cmd.disassemble.DisassembleCommand;
-import ghidra.app.plugin.core.debug.workflow.DisassemblyInject;
-import ghidra.app.plugin.core.debug.workflow.DisassemblyInjectInfo;
+import ghidra.app.plugin.core.debug.workflow.*;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.AddressSetView;
-import ghidra.program.model.lang.Register;
-import ghidra.program.model.lang.RegisterValue;
+import ghidra.program.model.lang.*;
+import ghidra.trace.model.Trace;
import ghidra.trace.model.memory.TraceMemoryRegisterSpace;
import ghidra.trace.model.memory.TraceMemoryState;
-import ghidra.trace.model.program.TraceProgramView;
import ghidra.trace.model.thread.TraceThread;
import ghidra.util.Msg;
@@ -61,36 +58,37 @@ public class ArmDisassemblyInject implements DisassemblyInject {
}
@Override
- public void pre(PluginTool tool, DisassembleCommand command, TraceProgramView view,
- TraceThread thread, AddressSetView startSet, AddressSetView restricted) {
+ public void pre(PluginTool tool, DisassembleTraceCommand command, Trace trace,
+ Language language, long snap, TraceThread thread, AddressSetView startSet,
+ AddressSetView restricted) {
/**
* TODO: There are probably several avenues to figure the TMode. The most important, I think
* is the cpsr register, when it's available. For auto-pc, the trace recorder ought to have
* recorded cpsr at the recorded tick.
*/
- Register cpsrReg = view.getLanguage().getRegister("cpsr");
- Register tModeReg = view.getLanguage().getRegister("TMode");
+ Register cpsrReg = language.getRegister("cpsr");
+ Register tModeReg = language.getRegister("TMode");
if (cpsrReg == null || tModeReg == null) {
- Msg.error(this, "No cpsr or TMode register in ARM language?: " +
- view.getLanguage().getLanguageID());
+ Msg.error(this,
+ "No cpsr or TMode register in ARM language?: " + language.getLanguageID());
return;
}
TraceMemoryRegisterSpace regs =
- view.getTrace().getMemoryManager().getMemoryRegisterSpace(thread, false);
+ trace.getMemoryManager().getMemoryRegisterSpace(thread, false);
/**
* Some variants (particularly Cortex-M) are missing cpsr This seems to indicate it only
* supports THUMB. There is an epsr (xpsr in gdb), but we don't have it in our models, and
* its TMode bit must be set, or it will fault.
*/
- if (regs == null || regs.getState(view.getSnap(), cpsrReg) != TraceMemoryState.KNOWN) {
+ if (regs == null || regs.getState(snap, cpsrReg) != TraceMemoryState.KNOWN) {
command.setInitialContext(new RegisterValue(tModeReg, BigInteger.ONE));
return;
}
- RegisterValue cpsrVal = regs.getValue(view.getSnap(), cpsrReg);
+ RegisterValue cpsrVal = regs.getValue(snap, cpsrReg);
if (isThumbMode(cpsrVal)) {
command.setInitialContext(new RegisterValue(tModeReg, BigInteger.ONE));
}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/dbgeng/DbgengDebuggerPlatformOpinion.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/dbgeng/DbgengDebuggerPlatformOpinion.java
new file mode 100644
index 0000000000..176f88a033
--- /dev/null
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/dbgeng/DbgengDebuggerPlatformOpinion.java
@@ -0,0 +1,83 @@
+/* ###
+ * 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.app.plugin.core.debug.platform.dbgeng;
+
+import java.util.Collection;
+import java.util.Set;
+
+import ghidra.app.plugin.core.debug.mapping.*;
+import ghidra.app.plugin.core.debug.workflow.DisassemblyInject;
+import ghidra.framework.plugintool.PluginTool;
+import ghidra.program.model.lang.*;
+import ghidra.trace.model.Trace;
+import ghidra.trace.model.target.TraceObject;
+
+public class DbgengDebuggerPlatformOpinion extends AbstractDebuggerPlatformOpinion {
+ protected static final LanguageID LANG_ID_X86_64 = new LanguageID("x86:LE:64:default");
+ protected static final CompilerSpecID COMP_ID_VS = new CompilerSpecID("windows");
+ protected static final Set INJECTS =
+ Set.of(new DbgengX64DisassemblyInject());
+
+ protected static class DbgengX64DebuggerPlatformMapper extends DefaultDebuggerPlatformMapper {
+ public DbgengX64DebuggerPlatformMapper(PluginTool tool, Trace trace, CompilerSpec cSpec) {
+ super(tool, trace, cSpec);
+ }
+ // TODO: Map registers: efl,rfl,rflags->eflags
+
+ @Override
+ protected Collection getDisassemblyInjections(TraceObject object) {
+ return INJECTS;
+ }
+ }
+
+ enum Offers implements DebuggerPlatformOffer {
+ // TODO: X86?
+ X64 {
+ @Override
+ public String getDescription() {
+ return "Dbgeng on Windows x64";
+ }
+
+ @Override
+ public int getConfidence() {
+ return 100;
+ }
+
+ @Override
+ public CompilerSpec getCompilerSpec() {
+ return getCompilerSpec(LANG_ID_X86_64, COMP_ID_VS);
+ }
+
+ @Override
+ public DebuggerPlatformMapper take(PluginTool tool, Trace trace) {
+ return new DbgengX64DebuggerPlatformMapper(tool, trace, getCompilerSpec());
+ }
+ };
+ }
+
+ @Override
+ protected Set getOffers(TraceObject object, long snap, TraceObject env,
+ String debugger, String arch, String os, Endian endian) {
+ if (debugger == null || arch == null || !debugger.toLowerCase().contains("dbg")) {
+ return Set.of();
+ }
+ boolean is64Bit = arch.contains("x86_64") || arch.contains("x64_32");
+ if (!is64Bit) {
+ return Set.of();
+ }
+ return Set.of(Offers.X64);
+ }
+}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/dbgeng/DbgengX64DisassemblyInject.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/dbgeng/DbgengX64DisassemblyInject.java
index 8e80b52395..e363bc812b 100644
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/dbgeng/DbgengX64DisassemblyInject.java
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/dbgeng/DbgengX64DisassemblyInject.java
@@ -22,21 +22,20 @@ import java.util.Set;
import java.util.concurrent.*;
import java.util.stream.Collectors;
-import ghidra.app.cmd.disassemble.DisassembleCommand;
-import ghidra.app.plugin.core.debug.workflow.DisassemblyInject;
-import ghidra.app.plugin.core.debug.workflow.DisassemblyInjectInfo;
+import ghidra.app.plugin.core.debug.workflow.*;
import ghidra.app.services.DebuggerModelService;
import ghidra.app.services.TraceRecorder;
-import ghidra.app.util.bin.MemoryByteProvider;
+import ghidra.app.util.bin.ByteProvider;
+import ghidra.app.util.bin.MemBufferByteProvider;
import ghidra.app.util.bin.format.pe.*;
import ghidra.app.util.bin.format.pe.PortableExecutable.SectionLayout;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.*;
+import ghidra.program.model.mem.MemBuffer;
import ghidra.program.util.ProgramContextImpl;
import ghidra.trace.model.Trace;
import ghidra.trace.model.modules.TraceModule;
-import ghidra.trace.model.program.TraceProgramView;
import ghidra.trace.model.thread.TraceThread;
import ghidra.util.Msg;
import ghidra.util.task.TaskMonitor;
@@ -50,9 +49,9 @@ public class DbgengX64DisassemblyInject implements DisassemblyInject {
}
@Override
- public void pre(PluginTool tool, DisassembleCommand command, TraceProgramView view,
- TraceThread thread, AddressSetView startSet, AddressSetView restricted) {
- Trace trace = view.getTrace();
+ public void pre(PluginTool tool, DisassembleTraceCommand command, Trace trace,
+ Language language, long snap, TraceThread thread, AddressSetView startSet,
+ AddressSetView restricted) {
AddressRange first = startSet.getFirstRange();
if (first == null) {
return;
@@ -60,20 +59,19 @@ public class DbgengX64DisassemblyInject implements DisassemblyInject {
DebuggerModelService modelService = tool.getService(DebuggerModelService.class);
TraceRecorder recorder = modelService == null ? null : modelService.getRecorder(trace);
Collection extends TraceModule> modules =
- trace.getModuleManager().getModulesAt(view.getSnap(), first.getMinAddress());
+ trace.getModuleManager().getModulesAt(snap, first.getMinAddress());
Set modes = modules.stream()
- .map(m -> modeForModule(recorder, view, m))
+ .map(m -> modeForModule(recorder, trace, snap, m))
.filter(m -> m != Mode.UNK)
.collect(Collectors.toSet());
if (modes.size() != 1) {
return;
}
Mode mode = modes.iterator().next();
- Language lang = trace.getBaseLanguage();
- Register addrsizeReg = lang.getRegister("addrsize");
- Register opsizeReg = lang.getRegister("opsize");
- ProgramContextImpl context = new ProgramContextImpl(lang);
- lang.applyContextSettings(context);
+ Register addrsizeReg = language.getRegister("addrsize");
+ Register opsizeReg = language.getRegister("opsize");
+ ProgramContextImpl context = new ProgramContextImpl(language);
+ language.applyContextSettings(context);
RegisterValue ctxVal = context.getDisassemblyContext(first.getMinAddress());
if (mode == Mode.X64) {
command.setInitialContext(ctxVal
@@ -88,9 +86,9 @@ public class DbgengX64DisassemblyInject implements DisassemblyInject {
// Shouldn't ever get anything else.
}
- protected Mode modeForModule(TraceRecorder recorder, TraceProgramView view,
+ protected Mode modeForModule(TraceRecorder recorder, Trace trace, long snap,
TraceModule module) {
- if (recorder != null && recorder.getSnap() == view.getSnap()) {
+ if (recorder != null && recorder.getSnap() == snap) {
AddressSet set = new AddressSet();
set.add(module.getBase(), module.getBase()); // Recorder should read page
try {
@@ -104,9 +102,10 @@ public class DbgengX64DisassemblyInject implements DisassemblyInject {
// Try to parse whatever's there. If 0s, it'll come UNK.
}
}
- MemoryByteProvider mbp = new MemoryByteProvider(view.getMemory(), module.getBase());
+ MemBuffer bufferAt = trace.getMemoryManager().getBufferAt(snap, module.getBase());
+ ByteProvider bp = new MemBufferByteProvider(bufferAt);
try {
- PortableExecutable pe = new PortableExecutable(mbp, SectionLayout.MEMORY, false, false);
+ PortableExecutable pe = new PortableExecutable(bp, SectionLayout.MEMORY, false, false);
NTHeader ntHeader = pe.getNTHeader();
if (ntHeader == null) {
return Mode.UNK;
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/arm/FridaArmDebuggerMappingOpinion.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/frida/FridaArmDebuggerMappingOpinion.java
similarity index 97%
rename from Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/arm/FridaArmDebuggerMappingOpinion.java
rename to Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/frida/FridaArmDebuggerMappingOpinion.java
index 44e50c831f..894c514c48 100644
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/arm/FridaArmDebuggerMappingOpinion.java
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/frida/FridaArmDebuggerMappingOpinion.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.plugin.core.debug.platform.arm;
+package ghidra.app.plugin.core.debug.platform.frida;
import java.util.Set;
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/frida/FridaDebuggerPlatformOpinion.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/frida/FridaDebuggerPlatformOpinion.java
new file mode 100644
index 0000000000..1ff3247f48
--- /dev/null
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/frida/FridaDebuggerPlatformOpinion.java
@@ -0,0 +1,134 @@
+/* ###
+ * 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.app.plugin.core.debug.platform.frida;
+
+import java.util.Set;
+
+import ghidra.app.plugin.core.debug.mapping.*;
+import ghidra.framework.plugintool.PluginTool;
+import ghidra.program.model.lang.*;
+import ghidra.trace.model.Trace;
+import ghidra.trace.model.target.TraceObject;
+
+public class FridaDebuggerPlatformOpinion extends AbstractDebuggerPlatformOpinion {
+ protected static final LanguageID LANG_ID_AARCH64 = new LanguageID("AARCH64:LE:64:v8A");
+ protected static final LanguageID LANG_ID_X86 = new LanguageID("x86:LE:32:default");
+ protected static final LanguageID LANG_ID_X86_64 = new LanguageID("x86:LE:64:default");
+ protected static final CompilerSpecID COMP_ID_DEFAULT = new CompilerSpecID("default");
+ protected static final CompilerSpecID COMP_ID_GCC = new CompilerSpecID("gcc");
+ protected static final CompilerSpecID COMP_ID_VS = new CompilerSpecID("windows");
+
+ protected static class FridaDebuggerPlatformMapper
+ extends DefaultDebuggerPlatformMapper {
+ public FridaDebuggerPlatformMapper(PluginTool tool, Trace trace,
+ CompilerSpec cSpec) {
+ super(tool, trace, cSpec);
+ }
+ // TODO: Map registers: rflags<->eflags for x86_64?
+ }
+
+ enum Offers implements DebuggerPlatformOffer {
+ AARCH64_MACOS("Frida on macOS Apple Silicon", LANG_ID_AARCH64, COMP_ID_DEFAULT),
+ I386_LINUX("Frida on Linux i386", LANG_ID_X86, COMP_ID_GCC),
+ I386_MACOS("Frida on macOS i386", LANG_ID_X86, COMP_ID_GCC),
+ I386_WINDOWS("Frida on Windows x86", LANG_ID_X86, COMP_ID_VS),
+ X86_64_LINUX("Frida on Linux x86_64", LANG_ID_X86_64, COMP_ID_GCC),
+ X86_64_MACOS("Frida on macOS x86_64", LANG_ID_X86_64, COMP_ID_GCC),
+ X86_64_WINDOWS("Frida on Windows x64", LANG_ID_X86_64, COMP_ID_VS);
+
+ final String description;
+ final LanguageID langID;
+ final CompilerSpecID cSpecID;
+
+ private Offers(String description, LanguageID langID, CompilerSpecID cSpecID) {
+ this.description = description;
+ this.langID = langID;
+ this.cSpecID = cSpecID;
+ }
+
+ @Override
+ public String getDescription() {
+ return description;
+ }
+
+ @Override
+ public int getConfidence() {
+ return 100;
+ }
+
+ @Override
+ public CompilerSpec getCompilerSpec() {
+ return getCompilerSpec(langID, cSpecID);
+ }
+
+ @Override
+ public DebuggerPlatformMapper take(PluginTool tool, Trace trace) {
+ // TODO: May need these per offer
+ return new FridaDebuggerPlatformMapper(tool, trace, getCompilerSpec());
+ }
+ }
+
+ @Override
+ protected Set getOffers(TraceObject object, long snap, TraceObject env,
+ String debugger, String arch, String os, Endian endian) {
+ if (debugger == null || arch == null ||
+ os == null | !debugger.toLowerCase().contains("frida")) {
+ return Set.of();
+ }
+ String lcOS = os.toLowerCase();
+ boolean isLinux = lcOS.contains("linux");
+ boolean isMacOS = lcOS.contains("darwin") || lcOS.contains("macos");
+ boolean isWindows = lcOS.contains("windows");
+ String lcArch = arch.toLowerCase();
+ // "arm" subsumes "arm64"
+ boolean isARM = lcArch.contains("aarch64") || lcArch.contains("arm");
+ boolean isI386 = lcArch.contains("ia32") || lcArch.contains("x86-32") ||
+ lcArch.contains("x86_32") || lcArch.contains("i386");
+ boolean isX86_64 = lcArch.contains("x64") || lcArch.contains("x86-64") ||
+ lcArch.contains("x86_64") || lcArch.contains("x64-32") || lcArch.contains("x64_32");
+ // TODO: i686? I'd think 32-bit,
+ // but it was listed as 64-bit in FridaX86DebuggerMappingOpinion
+
+ if (isLinux) {
+ if (isI386) {
+ return Set.of(Offers.I386_LINUX);
+ }
+ if (isX86_64) {
+ return Set.of(Offers.X86_64_LINUX);
+ }
+ }
+ if (isMacOS) {
+ if (isARM) {
+ return Set.of(Offers.AARCH64_MACOS);
+ }
+ if (isI386) {
+ return Set.of(Offers.I386_MACOS);
+ }
+ if (isX86_64) {
+ return Set.of(Offers.X86_64_MACOS);
+ }
+ }
+ if (isWindows) {
+ if (isI386) {
+ return Set.of(Offers.I386_WINDOWS);
+ }
+ if (isX86_64) {
+ return Set.of(Offers.X86_64_WINDOWS);
+ }
+ }
+ return Set.of();
+ }
+}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/arm/GdbArmDebuggerMappingOpinion.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/gdb/GdbArmDebuggerMappingOpinion.java
similarity index 95%
rename from Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/arm/GdbArmDebuggerMappingOpinion.java
rename to Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/gdb/GdbArmDebuggerMappingOpinion.java
index f64b045b44..66090dbb93 100644
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/arm/GdbArmDebuggerMappingOpinion.java
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/gdb/GdbArmDebuggerMappingOpinion.java
@@ -13,13 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.plugin.core.debug.platform.arm;
+package ghidra.app.plugin.core.debug.platform.gdb;
import java.util.Collection;
import java.util.Set;
import ghidra.app.plugin.core.debug.mapping.DebuggerMappingOffer;
-import ghidra.app.plugin.core.debug.platform.gdb.DefaultGdbDebuggerMappingOpinion;
import ghidra.dbg.target.TargetObject;
import ghidra.program.model.lang.*;
import ghidra.program.util.DefaultLanguageService;
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/gdb/GdbDebuggerPlatformOpinion.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/gdb/GdbDebuggerPlatformOpinion.java
new file mode 100644
index 0000000000..2b76447483
--- /dev/null
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/gdb/GdbDebuggerPlatformOpinion.java
@@ -0,0 +1,99 @@
+/* ###
+ * 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.app.plugin.core.debug.platform.gdb;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+import org.apache.commons.lang3.tuple.Pair;
+
+import ghidra.app.plugin.core.debug.mapping.*;
+import ghidra.framework.plugintool.PluginTool;
+import ghidra.program.model.lang.*;
+import ghidra.program.util.DefaultLanguageService;
+import ghidra.trace.model.Trace;
+import ghidra.trace.model.target.TraceObject;
+
+public class GdbDebuggerPlatformOpinion extends AbstractDebuggerPlatformOpinion {
+ public static final String EXTERNAL_TOOL = "gnu";
+ public static final CompilerSpecID PREFERRED_CSPEC_ID = new CompilerSpecID("gcc");
+
+ private static final Map, List> CACHE =
+ new HashMap<>();
+
+ public static List getCompilerSpecsForGnu(String arch,
+ Endian endian) {
+ synchronized (CACHE) {
+ return CACHE.computeIfAbsent(Pair.of(arch, endian), p -> {
+ LanguageService langServ = DefaultLanguageService.getLanguageService();
+ return langServ.getLanguageCompilerSpecPairs(
+ new ExternalLanguageCompilerSpecQuery(arch, EXTERNAL_TOOL,
+ endian, null, PREFERRED_CSPEC_ID));
+ });
+ }
+ }
+
+ protected static class GdbDebuggerPlatformOffer extends AbstractDebuggerPlatformOffer {
+ public static GdbDebuggerPlatformOffer fromArchLCSP(String arch,
+ LanguageCompilerSpecPair lcsp)
+ throws CompilerSpecNotFoundException, LanguageNotFoundException {
+ return new GdbDebuggerPlatformOffer("Default GDB for " + arch, lcsp.getCompilerSpec());
+ }
+
+ public GdbDebuggerPlatformOffer(String description, CompilerSpec cSpec) {
+ super(description, cSpec);
+ }
+
+ @Override
+ public int getConfidence() {
+ return 10;
+ }
+
+ @Override
+ public DebuggerPlatformMapper take(PluginTool tool, Trace trace) {
+ return new GdbDebuggerPlatformMapper(tool, trace, cSpec);
+ }
+ }
+
+ protected static class GdbDebuggerPlatformMapper extends DefaultDebuggerPlatformMapper {
+ public GdbDebuggerPlatformMapper(PluginTool tool, Trace trace, CompilerSpec cSpec) {
+ super(tool, trace, cSpec);
+ }
+ // TODO: eflags<->rflags for amd64 / x86-64
+ }
+
+ protected Set offersForLanguageAndCSpec(String arch, Endian endian,
+ LanguageCompilerSpecPair lcsp)
+ throws CompilerSpecNotFoundException, LanguageNotFoundException {
+ return Set.of(GdbDebuggerPlatformOffer.fromArchLCSP("Default GDB for " + arch, lcsp));
+ }
+
+ @Override
+ protected Set getOffers(TraceObject object, long snap, TraceObject env,
+ String debugger, String arch, String os, Endian endian) {
+ if (!"gdb".equals(debugger.toLowerCase())) {
+ return Set.of();
+ }
+ return getCompilerSpecsForGnu(arch, endian).stream().flatMap(lcsp -> {
+ try {
+ return offersForLanguageAndCSpec(arch, endian, lcsp).stream();
+ }
+ catch (CompilerSpecNotFoundException | LanguageNotFoundException e) {
+ throw new AssertionError(e);
+ }
+ }).collect(Collectors.toSet());
+ }
+}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/jvm/JdiDalvikDebuggerMappingOpinion.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/jdi/JdiDalvikDebuggerMappingOpinion.java
similarity index 98%
rename from Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/jvm/JdiDalvikDebuggerMappingOpinion.java
rename to Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/jdi/JdiDalvikDebuggerMappingOpinion.java
index e05b82e795..9ed15f80ee 100644
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/jvm/JdiDalvikDebuggerMappingOpinion.java
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/jdi/JdiDalvikDebuggerMappingOpinion.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.plugin.core.debug.platform.jvm;
+package ghidra.app.plugin.core.debug.platform.jdi;
import java.util.Collection;
import java.util.Set;
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/jdi/JdiDebuggerPlatformOpinion.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/jdi/JdiDebuggerPlatformOpinion.java
new file mode 100644
index 0000000000..a3a1345164
--- /dev/null
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/jdi/JdiDebuggerPlatformOpinion.java
@@ -0,0 +1,90 @@
+/* ###
+ * 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.app.plugin.core.debug.platform.jdi;
+
+import java.util.Set;
+
+import ghidra.app.plugin.core.debug.mapping.*;
+import ghidra.framework.plugintool.PluginTool;
+import ghidra.program.model.lang.*;
+import ghidra.trace.model.Trace;
+import ghidra.trace.model.target.TraceObject;
+
+public class JdiDebuggerPlatformOpinion extends AbstractDebuggerPlatformOpinion {
+ protected static final LanguageID LANG_ID_JAVA = new LanguageID("JVM:BE:32:default");
+ protected static final LanguageID LANG_ID_DALVIK = new LanguageID("Dalvik:LE:32:default");
+ protected static final CompilerSpecID COMP_ID_DEFAULT = new CompilerSpecID("default");
+
+ protected static class JdiDebuggerPlatformMapper extends DefaultDebuggerPlatformMapper {
+ // TODO: Delete this class?
+ public JdiDebuggerPlatformMapper(PluginTool tool, Trace trace, CompilerSpec cSpec) {
+ super(tool, trace, cSpec);
+ }
+ }
+
+ enum Offers implements DebuggerPlatformOffer {
+ JAVA_VM("Java Virtual Machine", LANG_ID_JAVA, COMP_ID_DEFAULT),
+ DALVIK_VM("Dalvik Virtual Machine", LANG_ID_DALVIK, COMP_ID_DEFAULT);
+
+ final String description;
+ final LanguageID langID;
+ final CompilerSpecID cSpecID;
+
+ private Offers(String description, LanguageID langID, CompilerSpecID cSpecID) {
+ this.description = description;
+ this.langID = langID;
+ this.cSpecID = cSpecID;
+ }
+
+ @Override
+ public String getDescription() {
+ return description;
+ }
+
+ @Override
+ public int getConfidence() {
+ return 100;
+ }
+
+ @Override
+ public CompilerSpec getCompilerSpec() {
+ return getCompilerSpec(langID, cSpecID);
+ }
+
+ @Override
+ public DebuggerPlatformMapper take(PluginTool tool, Trace trace) {
+ return new JdiDebuggerPlatformMapper(tool, trace, getCompilerSpec());
+ }
+ }
+
+ @Override
+ protected Set getOffers(TraceObject object, long snap, TraceObject env,
+ String debugger, String arch, String os, Endian endian) {
+ if (debugger == null || arch == null || !debugger.contains("Java Debug Interface")) {
+ return Set.of();
+ }
+ boolean isJava = arch.contains("OpenJDK");
+ boolean isDalvik = arch.contains("Dalvik");
+ // NOTE: Not worried about versions
+ if (isJava) {
+ return Set.of(Offers.JAVA_VM);
+ }
+ if (isDalvik) {
+ return Set.of(Offers.DALVIK_VM);
+ }
+ return Set.of();
+ }
+}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/jvm/JdiJavaDebuggerMappingOpinion.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/jdi/JdiJvmDebuggerMappingOpinion.java
similarity index 95%
rename from Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/jvm/JdiJavaDebuggerMappingOpinion.java
rename to Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/jdi/JdiJvmDebuggerMappingOpinion.java
index 8bcb5041b2..08449559e3 100644
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/jvm/JdiJavaDebuggerMappingOpinion.java
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/jdi/JdiJvmDebuggerMappingOpinion.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.plugin.core.debug.platform.jvm;
+package ghidra.app.plugin.core.debug.platform.jdi;
import java.util.Collection;
import java.util.Set;
@@ -22,7 +22,7 @@ import ghidra.app.plugin.core.debug.mapping.*;
import ghidra.dbg.target.*;
import ghidra.program.model.lang.*;
-public class JdiJavaDebuggerMappingOpinion implements DebuggerMappingOpinion {
+public class JdiJvmDebuggerMappingOpinion implements DebuggerMappingOpinion {
protected static final LanguageID LANG_ID_JAVA = new LanguageID("JVM:BE:32:default");
protected static final CompilerSpecID COMP_ID_VS = new CompilerSpecID("default");
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/arm/LldbArmDebuggerMappingOpinion.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/lldb/LldbArmDebuggerMappingOpinion.java
similarity index 98%
rename from Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/arm/LldbArmDebuggerMappingOpinion.java
rename to Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/lldb/LldbArmDebuggerMappingOpinion.java
index fa7d6e85a0..04842b9a1b 100644
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/arm/LldbArmDebuggerMappingOpinion.java
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/lldb/LldbArmDebuggerMappingOpinion.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.plugin.core.debug.platform.arm;
+package ghidra.app.plugin.core.debug.platform.lldb;
import java.util.Set;
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/lldb/LldbDebuggerPlatformOpinion.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/lldb/LldbDebuggerPlatformOpinion.java
new file mode 100644
index 0000000000..4548ba78fe
--- /dev/null
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/lldb/LldbDebuggerPlatformOpinion.java
@@ -0,0 +1,134 @@
+/* ###
+ * 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.app.plugin.core.debug.platform.lldb;
+
+import java.util.Set;
+
+import ghidra.app.plugin.core.debug.mapping.*;
+import ghidra.framework.plugintool.PluginTool;
+import ghidra.program.model.lang.*;
+import ghidra.trace.model.Trace;
+import ghidra.trace.model.target.TraceObject;
+
+public class LldbDebuggerPlatformOpinion extends AbstractDebuggerPlatformOpinion {
+ protected static final LanguageID LANG_ID_AARCH64 = new LanguageID("AARCH64:LE:64:v8A");
+ protected static final LanguageID LANG_ID_X86 = new LanguageID("x86:LE:32:default");
+ protected static final LanguageID LANG_ID_X86_64 = new LanguageID("x86:LE:64:default");
+ protected static final CompilerSpecID COMP_ID_DEFAULT = new CompilerSpecID("default");
+ protected static final CompilerSpecID COMP_ID_GCC = new CompilerSpecID("gcc");
+ protected static final CompilerSpecID COMP_ID_VS = new CompilerSpecID("windows");
+
+ protected static class LldbDebuggerPlatformMapper
+ extends DefaultDebuggerPlatformMapper {
+ public LldbDebuggerPlatformMapper(PluginTool tool, Trace trace,
+ CompilerSpec cSpec) {
+ super(tool, trace, cSpec);
+ }
+ // TODO: Map registers: rflags<->eflags for x86_64?
+ }
+
+ enum Offers implements DebuggerPlatformOffer {
+ AARCH64_MACOS("LLDB on macOS Apple Silicon", LANG_ID_AARCH64, COMP_ID_DEFAULT),
+ I386_LINUX("LLDB on Linux i386", LANG_ID_X86, COMP_ID_GCC),
+ I386_MACOS("LLDB on macOS i386", LANG_ID_X86, COMP_ID_GCC),
+ I386_WINDOWS("LLDB on Windows x86", LANG_ID_X86, COMP_ID_VS),
+ X86_64_LINUX("LLDB on Linux x86_64", LANG_ID_X86_64, COMP_ID_GCC),
+ X86_64_MACOS("LLDB on macOS x86_64", LANG_ID_X86_64, COMP_ID_GCC),
+ X86_64_WINDOWS("LLDB on Windows x64", LANG_ID_X86_64, COMP_ID_VS);
+
+ final String description;
+ final LanguageID langID;
+ final CompilerSpecID cSpecID;
+
+ private Offers(String description, LanguageID langID, CompilerSpecID cSpecID) {
+ this.description = description;
+ this.langID = langID;
+ this.cSpecID = cSpecID;
+ }
+
+ @Override
+ public String getDescription() {
+ return description;
+ }
+
+ @Override
+ public int getConfidence() {
+ return 100;
+ }
+
+ @Override
+ public CompilerSpec getCompilerSpec() {
+ return getCompilerSpec(langID, cSpecID);
+ }
+
+ @Override
+ public DebuggerPlatformMapper take(PluginTool tool, Trace trace) {
+ // TODO: May need these per offer
+ return new LldbDebuggerPlatformMapper(tool, trace, getCompilerSpec());
+ }
+ }
+
+ @Override
+ protected Set getOffers(TraceObject object, long snap, TraceObject env,
+ String debugger, String arch, String os, Endian endian) {
+ if (debugger == null || arch == null ||
+ os == null | !debugger.toLowerCase().contains("lldb")) {
+ return Set.of();
+ }
+ String lcOS = os.toLowerCase();
+ boolean isLinux = lcOS.contains("linux");
+ boolean isMacOS = lcOS.contains("darwin") || lcOS.contains("macos");
+ boolean isWindows = lcOS.contains("windows");
+ String lcArch = arch.toLowerCase();
+ // "arm" subsumes "arm64"
+ boolean isARM = lcArch.contains("aarch64") || lcArch.contains("arm");
+ boolean isI386 = lcArch.contains("ia32") || lcArch.contains("x86-32") ||
+ lcArch.contains("x86_32") || lcArch.contains("i386");
+ boolean isX86_64 = lcArch.contains("x64") || lcArch.contains("x86-64") ||
+ lcArch.contains("x86_64") || lcArch.contains("x64-32") || lcArch.contains("x64_32");
+ // TODO: i686? I'd think 32-bit,
+ // but it was listed as 64-bit in LldbX86DebuggerMappingOpinion
+
+ if (isLinux) {
+ if (isI386) {
+ return Set.of(Offers.I386_LINUX);
+ }
+ if (isX86_64) {
+ return Set.of(Offers.X86_64_LINUX);
+ }
+ }
+ if (isMacOS) {
+ if (isARM) {
+ return Set.of(Offers.AARCH64_MACOS);
+ }
+ if (isI386) {
+ return Set.of(Offers.I386_MACOS);
+ }
+ if (isX86_64) {
+ return Set.of(Offers.X86_64_MACOS);
+ }
+ }
+ if (isWindows) {
+ if (isI386) {
+ return Set.of(Offers.I386_WINDOWS);
+ }
+ if (isX86_64) {
+ return Set.of(Offers.X86_64_WINDOWS);
+ }
+ }
+ return Set.of();
+ }
+}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/launch/AbstractDebuggerProgramLaunchOffer.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/launch/AbstractDebuggerProgramLaunchOffer.java
index 8ccbc840e3..d64f1ed587 100644
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/launch/AbstractDebuggerProgramLaunchOffer.java
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/launch/AbstractDebuggerProgramLaunchOffer.java
@@ -516,6 +516,9 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg
() -> onTimedOutRecorder(monitor, service, t));
}).thenCompose(r -> {
monitor.incrementProgress(1);
+ if (r == null) {
+ throw new CancellationException();
+ }
monitor.setMessage("Confirming program is mapped to target");
CompletableFuture futureMapped = listenForMapping(mappingService, r);
return AsyncTimer.DEFAULT_TIMER.mark()
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/record/EmptyDebuggerRegisterMapper.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/record/EmptyDebuggerRegisterMapper.java
index 0713157671..e9224e9563 100644
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/record/EmptyDebuggerRegisterMapper.java
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/record/EmptyDebuggerRegisterMapper.java
@@ -50,7 +50,7 @@ public class EmptyDebuggerRegisterMapper implements DebuggerRegisterMapper {
@Override
public Set getRegistersOnTarget() {
- return null;
+ return Set.of();
}
@Override
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/platform/DebuggerPlatformServicePlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/platform/DebuggerPlatformServicePlugin.java
new file mode 100644
index 0000000000..fb64b1e1cc
--- /dev/null
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/platform/DebuggerPlatformServicePlugin.java
@@ -0,0 +1,139 @@
+/* ###
+ * 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.app.plugin.core.debug.service.platform;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import docking.action.builder.ActionBuilder;
+import ghidra.app.plugin.PluginCategoryNames;
+import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
+import ghidra.app.plugin.core.debug.event.TraceClosedPluginEvent;
+import ghidra.app.plugin.core.debug.gui.DebuggerResources.ChoosePlatformAction;
+import ghidra.app.plugin.core.debug.mapping.*;
+import ghidra.app.services.DebuggerPlatformService;
+import ghidra.app.services.DebuggerTraceManagerService;
+import ghidra.framework.plugintool.*;
+import ghidra.framework.plugintool.annotation.AutoServiceConsumed;
+import ghidra.framework.plugintool.util.PluginStatus;
+import ghidra.lifecycle.Unfinished;
+import ghidra.trace.model.Trace;
+import ghidra.trace.model.target.TraceObject;
+
+@PluginInfo(
+ shortDescription = "Debugger platform service plugin",
+ description = "Selects and manages platforms for the current focus",
+ category = PluginCategoryNames.DEBUGGER,
+ packageName = DebuggerPluginPackage.NAME,
+ status = PluginStatus.RELEASED,
+ eventsConsumed = {
+ TraceClosedPluginEvent.class,
+ },
+ servicesRequired = {
+ DebuggerTraceManagerService.class,
+ },
+ servicesProvided = {
+ DebuggerPlatformService.class,
+ })
+public class DebuggerPlatformServicePlugin extends Plugin implements DebuggerPlatformService {
+
+ @AutoServiceConsumed
+ private DebuggerTraceManagerService traceManager;
+ @SuppressWarnings("unused")
+ private final AutoService.Wiring autoServiceWiring;
+
+ ActionBuilder actionChoosePlatform;
+
+ private final Map mappersByTrace = new HashMap<>();
+
+ public DebuggerPlatformServicePlugin(PluginTool tool) {
+ super(tool);
+ this.autoServiceWiring = AutoService.wireServicesProvidedAndConsumed(this);
+ }
+
+ @Override
+ protected void init() {
+ super.init();
+ createActions();
+ }
+
+ protected void createActions() {
+ actionChoosePlatform = ChoosePlatformAction.builder(this); // TODO:
+ }
+
+ @Override
+ public DebuggerPlatformMapper getMapper(Trace trace, TraceObject object, long snap) {
+ /**
+ * TODO: There's a chance different components fight over the current mapper. However, I
+ * suspect all nodes in a trace will yield the same offers, so perhaps I should not worry.
+ */
+ DebuggerPlatformMapper mapper;
+ synchronized (mappersByTrace) {
+ mapper = mappersByTrace.get(trace);
+ if (mapper != null && mapper.canInterpret(object, snap)) {
+ return mapper;
+ }
+ mapper = getNewMapper(trace, object, snap);
+ if (mapper == null) {
+ return null;
+ }
+ mappersByTrace.put(trace, mapper);
+ }
+ mapper.addToTrace(snap);
+ // TODO: Fire a listener
+ return mapper;
+ }
+
+ @Override
+ public DebuggerPlatformMapper getNewMapper(Trace trace, TraceObject object, long snap) {
+ if (!traceManager.getOpenTraces().contains(trace)) {
+ throw new IllegalArgumentException("Trace is not opened in this tool");
+ }
+ for (DebuggerPlatformOffer offer : DebuggerPlatformOpinion.queryOpinions(trace, object,
+ snap, false)) {
+ return offer.take(tool, trace);
+ }
+ return null;
+ }
+
+ @Override
+ public DebuggerPlatformMapper chooseMapper(Trace trace, TraceObject object, long snap) {
+ return Unfinished.TODO();
+ }
+
+ @Override
+ public void setCurrentMapperFor(Trace trace, DebuggerPlatformMapper mapper, long snap) {
+ if (!traceManager.getOpenTraces().contains(trace)) {
+ throw new IllegalArgumentException("Trace is not opened in this tool");
+ }
+ synchronized (mappersByTrace) {
+ mappersByTrace.put(trace, mapper);
+ }
+ mapper.addToTrace(snap);
+ // TODO: Fire a listener
+ }
+
+ @Override
+ public void processEvent(PluginEvent event) {
+ super.processEvent(event);
+ if (event instanceof TraceClosedPluginEvent) {
+ TraceClosedPluginEvent ev = (TraceClosedPluginEvent) event;
+ synchronized (mappersByTrace) {
+ mappersByTrace.remove(ev.getTrace());
+ }
+ }
+ }
+}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/workflow/DisassembleAtPcDebuggerBot.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/workflow/DisassembleAtPcDebuggerBot.java
index 5370389b50..8130f49b1e 100644
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/workflow/DisassembleAtPcDebuggerBot.java
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/workflow/DisassembleAtPcDebuggerBot.java
@@ -22,12 +22,15 @@ import javax.swing.event.ChangeListener;
import com.google.common.collect.Range;
-import ghidra.app.cmd.disassemble.DisassembleCommand;
+import docking.DockingWindowManager;
+import docking.Tool;
+import ghidra.app.plugin.core.debug.mapping.DebuggerPlatformMapper;
+import ghidra.app.plugin.core.debug.mapping.DisassemblyResult;
import ghidra.app.plugin.core.debug.service.workflow.*;
-import ghidra.app.services.DebuggerBot;
-import ghidra.app.services.DebuggerBotInfo;
+import ghidra.app.services.*;
import ghidra.async.AsyncDebouncer;
import ghidra.async.AsyncTimer;
+import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.model.DomainObject;
import ghidra.framework.options.annotation.HelpInfo;
import ghidra.framework.plugintool.PluginTool;
@@ -43,6 +46,8 @@ import ghidra.trace.model.listing.*;
import ghidra.trace.model.memory.*;
import ghidra.trace.model.program.TraceProgramView;
import ghidra.trace.model.stack.*;
+import ghidra.trace.model.target.TraceObject;
+import ghidra.trace.model.thread.TraceObjectThread;
import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.util.*;
import ghidra.util.*;
@@ -207,14 +212,18 @@ public class DisassembleAtPcDebuggerBot implements DebuggerBot {
if (pcVal == null) {
return;
}
- if (range == null || range.contains(pcVal)) {
- // NOTE: If non-0 frames are ever used, level should be passed in for injects
- disassemble(pcVal, stack.getThread(), snap);
+ if (range != null && !range.contains(pcVal)) {
+ return;
}
+ // NOTE: If non-0 frames are ever used, level should be passed in for injects
+ disassemble(pcVal, stack.getThread(), snap);
}
protected void disassembleRegPcVal(TraceThread thread, int frameLevel, long pcSnap,
long memSnap) {
+ if (pc == null) {
+ return;
+ }
TraceData pcUnit = null;
try (UndoableTransaction tid =
UndoableTransaction.start(trace, "Disassemble: PC is code pointer", true)) {
@@ -258,6 +267,14 @@ public class DisassembleAtPcDebuggerBot implements DebuggerBot {
return mrent.getKey().getY1();
}
+ // TODO: TraceManager should instead track focus object, not thread
+ protected TraceObject getObject(TraceThread thread) {
+ if (!(thread instanceof TraceObjectThread)) {
+ return null;
+ }
+ return ((TraceObjectThread) thread).getObject();
+ }
+
protected void disassemble(Address start, TraceThread thread, long snap) {
Long knownSnap = isKnownRWOrEverKnownRO(start, snap);
if (knownSnap == null) {
@@ -290,39 +307,39 @@ public class DisassembleAtPcDebuggerBot implements DebuggerBot {
// TODO: Should I just keep a variable-snap view around?
TraceProgramView view = trace.getFixedProgramView(ks);
- DisassembleCommand dis =
- new DisassembleCommand(start, disassemblable, true) {
- @Override
- public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
- synchronized (injects) {
- try {
- if (codeManager.definedUnits().containsAddress(ks, start)) {
- return true;
- }
- for (DisassemblyInject i : injects) {
- i.pre(plugin.getTool(), this, view, thread,
- new AddressSet(start, start),
- disassemblable);
- }
- boolean result = super.applyTo(obj, monitor);
- if (!result) {
- Msg.error(this, "Auto-disassembly error: " + getStatusMsg());
- return true; // No pop-up errors
- }
- for (DisassemblyInject i : injects) {
- i.post(plugin.getTool(), view, getDisassembledAddressSet());
- }
- return true;
- }
- catch (Throwable e) {
- Msg.error(this, "Auto-disassembly error: " + e);
- return true; // No pop-up errors
- }
+
+ BackgroundCommand cmd = new BackgroundCommand("Auto-disassemble", true, true, false) {
+ @Override
+ public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
+ try {
+ DebuggerPlatformService platformService =
+ findService(DebuggerPlatformService.class);
+ if (platformService == null) {
+ reportError("Cannot disassemble without the platform service");
+ return true;
}
+ TraceObject object = getObject(thread);
+ DebuggerPlatformMapper mapper =
+ platformService.getMapper(trace, object, snap);
+ if (mapper == null) {
+ reportError("Cannot disassemble without a platform mapper");
+ return true;
+ }
+ DisassemblyResult result = mapper.disassemble(thread, object, start,
+ disassemblable, snap, monitor);
+ if (result.isAtLeastOne() || result.isSuccess()) {
+ return true;
+ }
+ reportError("Auto-disassembly error: " + result.getErrorMessage());
}
- };
+ catch (Exception e) {
+ reportError("Auto-disassembly error: " + e, e);
+ }
+ return true; // No pop-up errors
+ }
+ };
// TODO: Queue commands so no two for the same trace run concurrently
- plugin.getTool().executeBackgroundCommand(dis, view);
+ plugin.getTool().executeBackgroundCommand(cmd, view);
}
}
@@ -330,6 +347,47 @@ public class DisassembleAtPcDebuggerBot implements DebuggerBot {
private final MultiToolTraceListenerManager listeners =
new MultiToolTraceListenerManager<>(ForDisassemblyTraceListener::new);
+ protected void reportError(String error) {
+ reportError(error, null);
+ }
+
+ protected void reportError(String error, Throwable t) {
+ for (PluginTool tool : plugin.getProxyingPluginTools()) {
+ Msg.error(this, error, t);
+ tool.setStatusInfo(error, true);
+ }
+ }
+
+ /**
+ * Find the given service among the open tools
+ *
+ *
+ * NOTE: This will prefer the service from the most-recently active tool first, only considering
+ * those with the workflow service proxy enabled. This is important when considering the state
+ * of said service.
+ *
+ * @param the type of the service
+ * @param cls the class of the service
+ * @return the service, or null
+ */
+ protected T findService(Class cls) {
+ Collection proxied = plugin.getProxyingPluginTools();
+ List all = DockingWindowManager.getAllDockingWindowManagers();
+ Collections.reverse(all);
+ for (DockingWindowManager dwm : all) {
+ Tool tool = dwm.getTool();
+ if (!proxied.contains(tool)) {
+ continue;
+ }
+ T t = tool.getService(cls);
+ if (t == null) {
+ continue;
+ }
+ return t;
+ }
+ return null;
+ }
+
@Override
public boolean isEnabled() {
return plugin != null;
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/workflow/DisassembleGuestTraceCommand.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/workflow/DisassembleGuestTraceCommand.java
new file mode 100644
index 0000000000..e388783a96
--- /dev/null
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/workflow/DisassembleGuestTraceCommand.java
@@ -0,0 +1,59 @@
+/* ###
+ * 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.app.plugin.core.debug.workflow;
+
+import com.google.common.collect.Range;
+
+import ghidra.program.disassemble.Disassembler;
+import ghidra.program.model.address.Address;
+import ghidra.program.model.address.AddressSetView;
+import ghidra.program.model.lang.InstructionBlock;
+import ghidra.program.model.lang.InstructionSet;
+import ghidra.program.model.mem.MemBuffer;
+import ghidra.trace.model.guest.TraceGuestPlatform;
+import ghidra.trace.model.program.TraceProgramView;
+import ghidra.util.task.TaskMonitor;
+
+public class DisassembleGuestTraceCommand extends DisassembleTraceCommand {
+ protected final TraceGuestPlatform guest;
+
+ public DisassembleGuestTraceCommand(TraceGuestPlatform guest, Address start,
+ AddressSetView restrictedSet) {
+ super(start, restrictedSet);
+ this.guest = guest;
+ }
+
+ @Override
+ protected Disassembler getDisassembler(TraceProgramView view, TaskMonitor monitor) {
+ return Disassembler.getDisassembler(guest.getLanguage(), guest.getAddressFactory(), monitor,
+ monitor::setMessage);
+ }
+
+ @Override
+ protected MemBuffer getBuffer(TraceProgramView view) {
+ return guest.getMappedMemBuffer(view.getSnap(), guest.mapHostToGuest(start));
+ }
+
+ @Override
+ protected AddressSetView writeBlock(TraceProgramView view, InstructionBlock block) {
+ InstructionSet set = new InstructionSet(guest.getAddressFactory());
+ set.addBlock(block);
+ return view.getTrace()
+ .getCodeManager()
+ .instructions()
+ .addInstructionSet(Range.atLeast(view.getSnap()), guest, set, true);
+ }
+}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/workflow/DisassembleTraceCommand.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/workflow/DisassembleTraceCommand.java
new file mode 100644
index 0000000000..f0a9481248
--- /dev/null
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/workflow/DisassembleTraceCommand.java
@@ -0,0 +1,94 @@
+/* ###
+ * 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.app.plugin.core.debug.workflow;
+
+import ghidra.framework.cmd.TypedBackgroundCommand;
+import ghidra.program.disassemble.Disassembler;
+import ghidra.program.model.address.*;
+import ghidra.program.model.lang.*;
+import ghidra.program.model.mem.MemBuffer;
+import ghidra.program.model.mem.MemoryBufferImpl;
+import ghidra.program.model.util.CodeUnitInsertionException;
+import ghidra.trace.model.guest.TraceGuestPlatform;
+import ghidra.trace.model.program.TraceProgramView;
+import ghidra.util.MathUtilities;
+import ghidra.util.task.TaskMonitor;
+
+public class DisassembleTraceCommand extends TypedBackgroundCommand {
+ public static DisassembleTraceCommand create(TraceGuestPlatform guest, Address start,
+ AddressSetView restrictedSet) {
+ return guest == null ? new DisassembleTraceCommand(start, restrictedSet)
+ : new DisassembleGuestTraceCommand(guest, start, restrictedSet);
+ }
+
+ protected final Address start;
+ protected final AddressSetView restrictedSet;
+
+ protected RegisterValue initialContext;
+ private AddressSetView disassembled;
+
+ public DisassembleTraceCommand(Address start, AddressSetView restrictedSet) {
+ super("Disassemble", true, true, false);
+ this.start = start;
+ this.restrictedSet = restrictedSet;
+ }
+
+ public void setInitialContext(RegisterValue initialContext) {
+ this.initialContext = initialContext.getBaseRegisterValue();
+ }
+
+ protected Disassembler getDisassembler(TraceProgramView view, TaskMonitor monitor) {
+ return Disassembler.getDisassembler(view, monitor, monitor::setMessage);
+ }
+
+ protected MemBuffer getBuffer(TraceProgramView view) {
+ return new MemoryBufferImpl(view.getMemory(), start);
+ }
+
+ protected int computeLimit() {
+ AddressRange range = restrictedSet.getRangeContaining(start);
+ if (range == null) {
+ return 1;
+ }
+ return MathUtilities.unsignedMin(range.getMaxAddress().subtract(start) + 1,
+ Integer.MAX_VALUE);
+ }
+
+ protected AddressSetView writeBlock(TraceProgramView view, InstructionBlock block) {
+ InstructionSet set = new InstructionSet(view.getAddressFactory());
+ set.addBlock(block);
+ try {
+ return view.getListing().addInstructions(set, true);
+ }
+ catch (CodeUnitInsertionException e) {
+ return new AddressSet();
+ }
+ }
+
+ @Override
+ public boolean applyToTyped(TraceProgramView view, TaskMonitor monitor) {
+ Disassembler disassembler = getDisassembler(view, monitor);
+ MemBuffer buffer = getBuffer(view);
+ int limit = computeLimit();
+ InstructionBlock block = disassembler.pseudoDisassembleBlock(buffer, initialContext, limit);
+ disassembled = writeBlock(view, block);
+ return true;
+ }
+
+ public AddressSetView getDisassembledAddressSet() {
+ return disassembled;
+ }
+}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/workflow/DisassemblyInject.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/workflow/DisassemblyInject.java
index 6bf587380f..eda4a799f8 100644
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/workflow/DisassemblyInject.java
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/workflow/DisassemblyInject.java
@@ -17,11 +17,10 @@ package ghidra.app.plugin.core.debug.workflow;
import java.util.Arrays;
-import ghidra.app.cmd.disassemble.DisassembleCommand;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.AddressSetView;
+import ghidra.program.model.lang.Language;
import ghidra.trace.model.Trace;
-import ghidra.trace.model.program.TraceProgramView;
import ghidra.trace.model.thread.TraceThread;
import ghidra.util.Msg;
import ghidra.util.classfinder.ExtensionPoint;
@@ -87,13 +86,16 @@ public interface DisassemblyInject extends ExtensionPoint {
*
* @param tool the tool that will execute the command
* @param command the command to be configured, which is about to execute
- * @param view the view (trace, snap) which is about to be disassembled
+ * @param trace the trace whose bytes to disassemble
+ * @param language the language for the disassembler
+ * @param snap the snap the snap at which to disassemble
* @param thread the thread whose PC is being disassembled
* @param startSet the starting address set, usually just the PC
* @param restricted the set of disassemblable addresses
*/
- default void pre(PluginTool tool, DisassembleCommand command, TraceProgramView view,
- TraceThread thread, AddressSetView startSet, AddressSetView restricted) {
+ default void pre(PluginTool tool, DisassembleTraceCommand command, Trace trace,
+ Language language, long snap, TraceThread thread, AddressSetView startSet,
+ AddressSetView restricted) {
}
/**
@@ -104,9 +106,10 @@ public interface DisassemblyInject extends ExtensionPoint {
* The callback occurs within the command's background thread.
*
* @param tool the tool that just executed the disassembly command
- * @param view the view (trace, snap) which was just disassembled
+ * @param trace the trace whose bytes were disassembled
+ * @param snap the snap the snap at which disassembly was performed
* @param disassembled the addresses that were actually disassembled
*/
- default void post(PluginTool tool, TraceProgramView view, AddressSetView disassembled) {
+ default void post(PluginTool tool, Trace trace, long snap, AddressSetView disassembled) {
}
}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/services/DebuggerPlatformService.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/services/DebuggerPlatformService.java
new file mode 100644
index 0000000000..7dab95f9b4
--- /dev/null
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/services/DebuggerPlatformService.java
@@ -0,0 +1,74 @@
+/* ###
+ * 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.app.services;
+
+import ghidra.app.plugin.core.debug.mapping.DebuggerPlatformMapper;
+import ghidra.trace.model.Trace;
+import ghidra.trace.model.target.TraceObject;
+
+/**
+ * A service to manage the current mapper for active traces
+ */
+public interface DebuggerPlatformService {
+ /**
+ * Get a mapper applicable to the given object
+ *
+ *
+ * If the trace's current mapper is applicable to the object, it will be returned. Otherwise,
+ * the service will query the opinions for a new mapper, as in
+ * {@link #getNewMapper(TraceObject)} and set it as the current mapper before returning. If a
+ * new mapper is set, the trace is also initialized for that mapper.
+ *
+ * @param trace the trace
+ * @param object the object for which a mapper is desired
+ * @param snap the snap, usually the current snap
+ * @return the mapper, or null if no offer was provided
+ */
+ DebuggerPlatformMapper getMapper(Trace trace, TraceObject object,
+ long snap);
+
+ /**
+ * Get a new mapper for the given object, ignoring the trace's current mapper
+ *
+ *
+ * This will not replace the trace's current mapper, nor will it initialize the trace for the
+ * mapper.
+ *
+ * @param trace the trace
+ * @param object the object for which a mapper is desired
+ * @param snap the snap, usually the current snap
+ * @return the mapper, or null if no offer was provided
+ */
+ DebuggerPlatformMapper getNewMapper(Trace trace, TraceObject object, long snap);
+
+ /**
+ * Display a dialog for the user to manually select a mapper for the given object
+ *
+ * @param object the object for which a mapper is desired
+ * @param snap the snap, usually the current snap
+ * @return the mapper, or null if the dialog was cancelled
+ */
+ DebuggerPlatformMapper chooseMapper(Trace trace, TraceObject object, long snap);
+
+ /**
+ * Set the current mapper for the trace and initialize the trace for the mapper
+ *
+ * @param trace the trace whose current mapper to set
+ * @param mapper the mapper
+ * @param snap the snap for initializing the trace
+ */
+ void setCurrentMapperFor(Trace trace, DebuggerPlatformMapper mapper, long snap);
+}
diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/DebuggerManualTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/DebuggerManualTest.java
index 9ee084271b..8976499190 100644
--- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/DebuggerManualTest.java
+++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/DebuggerManualTest.java
@@ -45,7 +45,7 @@ import ghidra.program.model.data.Undefined4DataType;
import ghidra.program.model.lang.Language;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.trace.database.ToyDBTraceBuilder;
-import ghidra.trace.database.language.DBTraceGuestLanguage;
+import ghidra.trace.database.guest.DBTraceGuestPlatform;
import ghidra.trace.model.memory.TraceMemoryFlag;
import ghidra.trace.model.memory.TraceOverlappedRegionException;
import ghidra.util.database.UndoableTransaction;
@@ -129,12 +129,13 @@ public class DebuggerManualTest extends AbstractGhidraHeadedDebuggerGUITest {
tb.trace.getThreadManager().createThread("Thread 2", 4);
tb.addData(0, tb.addr(0x4004), Undefined4DataType.dataType, tb.buf(6, 7, 8, 9));
- tb.addInstruction(0, tb.addr(0x4008), tb.language, tb.buf(0xf4, 0));
+ tb.addInstruction(0, tb.addr(0x4008), null, tb.buf(0xf4, 0));
Language x86 = getSLEIGH_X86_LANGUAGE();
- DBTraceGuestLanguage guest = tb.trace.getLanguageManager().addGuestLanguage(x86);
+ DBTraceGuestPlatform guest =
+ tb.trace.getPlatformManager().addGuestPlatform(x86.getDefaultCompilerSpec());
guest.addMappedRange(tb.addr(0x4000), tb.addr(guest, 0x00400000), 0x1000);
- tb.addInstruction(0, tb.addr(0x400a), x86, tb.buf(0x90));
+ tb.addInstruction(0, tb.addr(0x400a), guest, tb.buf(0x90));
}
waitForSwing();
diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/mapping/TestDebuggerPlatformOpinion.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/mapping/TestDebuggerPlatformOpinion.java
new file mode 100644
index 0000000000..4ffa1408df
--- /dev/null
+++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/mapping/TestDebuggerPlatformOpinion.java
@@ -0,0 +1,62 @@
+/* ###
+ * 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.app.plugin.core.debug.mapping;
+
+import java.util.Set;
+
+import ghidra.framework.plugintool.PluginTool;
+import ghidra.program.model.lang.*;
+import ghidra.trace.model.Trace;
+import ghidra.trace.model.target.TraceObject;
+
+public class TestDebuggerPlatformOpinion extends AbstractDebuggerPlatformOpinion {
+
+ enum Offers implements DebuggerPlatformOffer {
+ X86_64 {
+ @Override
+ public String getDescription() {
+ return "Test x86-64";
+ }
+
+ @Override
+ public int getConfidence() {
+ return 1;
+ }
+
+ @Override
+ public CompilerSpec getCompilerSpec() {
+ return getCompilerSpec(new LanguageID("x86:LE:64:default"), null);
+ }
+
+ @Override
+ public DebuggerPlatformMapper take(PluginTool tool, Trace trace) {
+ return new DefaultDebuggerPlatformMapper(tool, trace, getCompilerSpec());
+ }
+ };
+ }
+
+ @Override
+ protected Set getOffers(TraceObject object, long snap,
+ TraceObject env, String debugger, String arch, String os, Endian endian) {
+ if (!"test".equals(debugger)) {
+ return Set.of();
+ }
+ if (!"x86-64".equals(arch)) {
+ return Set.of();
+ }
+ return Set.of(Offers.X86_64);
+ }
+}
diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/platform/arm/GdbArmDebuggerMappingOpinionTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/platform/gdb/GdbArmDebuggerMappingOpinionTest.java
similarity index 95%
rename from Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/platform/arm/GdbArmDebuggerMappingOpinionTest.java
rename to Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/platform/gdb/GdbArmDebuggerMappingOpinionTest.java
index a216515b1a..af7a580cc1 100644
--- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/platform/arm/GdbArmDebuggerMappingOpinionTest.java
+++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/platform/gdb/GdbArmDebuggerMappingOpinionTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.plugin.core.debug.platform.arm;
+package ghidra.app.plugin.core.debug.platform.gdb;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -25,8 +25,8 @@ import org.junit.Test;
import ghidra.app.plugin.core.debug.mapping.DebuggerMappingOffer;
import ghidra.app.plugin.core.debug.mapping.DebuggerMappingOpinion;
-import ghidra.app.plugin.core.debug.platform.arm.GdbArmDebuggerMappingOpinion.GdbAArch64Offer;
-import ghidra.app.plugin.core.debug.platform.arm.GdbArmDebuggerMappingOpinion.GdbArmOffer;
+import ghidra.app.plugin.core.debug.platform.gdb.GdbArmDebuggerMappingOpinion.GdbAArch64Offer;
+import ghidra.app.plugin.core.debug.platform.gdb.GdbArmDebuggerMappingOpinion.GdbArmOffer;
import ghidra.dbg.model.TestDebuggerObjectModel;
import ghidra.dbg.model.TestTargetProcess;
import ghidra.program.model.lang.LanguageID;
diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/workflow/DisassembleAtPcDebuggerBotTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/workflow/DisassembleAtPcDebuggerBotTest.java
new file mode 100644
index 0000000000..1f54d312df
--- /dev/null
+++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/workflow/DisassembleAtPcDebuggerBotTest.java
@@ -0,0 +1,168 @@
+/* ###
+ * 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.app.plugin.core.debug.workflow;
+
+import static org.junit.Assert.*;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.collect.Range;
+
+import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
+import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingPlugin;
+import ghidra.app.plugin.core.debug.service.platform.DebuggerPlatformServicePlugin;
+import ghidra.app.plugin.core.debug.service.workflow.DebuggerWorkflowServiceProxyPlugin;
+import ghidra.app.services.DebuggerBot;
+import ghidra.app.services.DebuggerWorkflowService;
+import ghidra.dbg.target.TargetEnvironment;
+import ghidra.dbg.target.schema.SchemaContext;
+import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
+import ghidra.dbg.target.schema.XmlSchemaContext;
+import ghidra.program.model.listing.Instruction;
+import ghidra.trace.database.listing.DBTraceInstructionsMemoryView;
+import ghidra.trace.database.memory.DBTraceMemoryManager;
+import ghidra.trace.database.target.DBTraceObject;
+import ghidra.trace.database.target.DBTraceObjectManager;
+import ghidra.trace.model.memory.TraceMemoryFlag;
+import ghidra.trace.model.memory.TraceObjectMemoryRegion;
+import ghidra.trace.model.stack.TraceObjectStackFrame;
+import ghidra.trace.model.target.TraceObject.ConflictResolution;
+import ghidra.trace.model.target.TraceObjectKeyPath;
+import ghidra.trace.model.thread.TraceObjectThread;
+import ghidra.util.database.UndoableTransaction;
+
+public class DisassembleAtPcDebuggerBotTest extends AbstractGhidraHeadedDebuggerGUITest {
+ protected SchemaContext ctx;
+
+ @Before
+ public void setUpDisassembleAtPcTest() throws Exception {
+ ctx = XmlSchemaContext.deserialize("" + //
+ "" + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ " " + //
+ "");
+
+ DebuggerWorkflowService workflowService =
+ addPlugin(tool, DebuggerWorkflowServiceProxyPlugin.class);
+ addPlugin(tool, DebuggerListingPlugin.class);
+ addPlugin(tool, DebuggerPlatformServicePlugin.class);
+
+ Set disBot = workflowService.getAllBots()
+ .stream()
+ .filter(b -> b instanceof DisassembleAtPcDebuggerBot)
+ .collect(Collectors.toSet());
+ assertEquals(1, disBot.size());
+ workflowService.enableBots(disBot);
+ }
+
+ protected void assertX86Nop(Instruction instruction) {
+ assertNotNull(instruction);
+ assertEquals("NOP", instruction.getMnemonicString());
+ }
+
+ @Test
+ public void testDisassembleX8664() throws Throwable {
+ createAndOpenTrace("DATA:BE:64:default");
+
+ DBTraceObjectManager objects = tb.trace.getObjectManager();
+ try (UndoableTransaction tid = tb.startTransaction()) {
+ objects.createRootObject(ctx.getSchema(new SchemaName("Session")));
+ DBTraceObject env =
+ objects.createObject(TraceObjectKeyPath.parse("Targets[0].Environment"));
+ assertEquals(ctx.getSchema(new SchemaName("Environment")), env.getTargetSchema());
+ Range zeroOn = Range.atLeast(0L);
+ env.insert(zeroOn, ConflictResolution.DENY);
+ env.setAttribute(zeroOn, TargetEnvironment.DEBUGGER_ATTRIBUTE_NAME, "test");
+ env.setAttribute(zeroOn, TargetEnvironment.ARCH_ATTRIBUTE_NAME, "x86-64");
+
+ DBTraceObject objBinText =
+ objects.createObject(TraceObjectKeyPath.parse("Targets[0].Memory[bin:.text]"));
+ TraceObjectMemoryRegion binText =
+ objBinText.queryInterface(TraceObjectMemoryRegion.class);
+ binText.addFlags(zeroOn, Set.of(TraceMemoryFlag.EXECUTE));
+ binText.setRange(zeroOn, tb.range(0x00400000, 0x0040ffff));
+ // TODO: Why doesn't setRange work after insert?
+ objBinText.insert(zeroOn, ConflictResolution.DENY);
+
+ DBTraceObject objFrame =
+ objects.createObject(TraceObjectKeyPath.parse("Targets[0].Threads[0].Stack[0]"));
+ objFrame.insert(zeroOn, ConflictResolution.DENY);
+ TraceObjectStackFrame frame = objFrame.queryInterface(TraceObjectStackFrame.class);
+ frame.setProgramCounter(zeroOn, tb.addr(0x00400000));
+
+ DBTraceMemoryManager memory = tb.trace.getMemoryManager();
+ memory.putBytes(0, tb.addr(0x00400000), tb.buf(0x90, 0x90, 0x90));
+ }
+ TraceObjectThread thread =
+ objects.getObjectByCanonicalPath(TraceObjectKeyPath.parse("Targets[0].Threads[0]"))
+ .queryInterface(TraceObjectThread.class);
+ traceManager.activateThread(thread);
+
+ getSLEIGH_X86_64_LANGUAGE(); // So that the load isn't charged against the time-out
+
+ waitForPass(() -> {
+ DBTraceInstructionsMemoryView instructions = tb.trace.getCodeManager().instructions();
+ assertX86Nop(instructions.getAt(0, tb.addr(0x00400000)));
+ assertX86Nop(instructions.getAt(0, tb.addr(0x00400001)));
+ assertX86Nop(instructions.getAt(0, tb.addr(0x00400002)));
+ assertNull(instructions.getAt(0, tb.addr(0x00400003)));
+ });
+ }
+}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTrace.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTrace.java
index 8fd0e18bb2..7431972f8f 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTrace.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTrace.java
@@ -38,7 +38,7 @@ import ghidra.trace.database.breakpoint.DBTraceBreakpointManager;
import ghidra.trace.database.context.DBTraceRegisterContextManager;
import ghidra.trace.database.data.DBTraceDataSettingsAdapter;
import ghidra.trace.database.data.DBTraceDataTypeManager;
-import ghidra.trace.database.language.DBTraceLanguageManager;
+import ghidra.trace.database.guest.DBTracePlatformManager;
import ghidra.trace.database.listing.DBTraceCodeManager;
import ghidra.trace.database.listing.DBTraceCommentAdapter;
import ghidra.trace.database.memory.DBTraceMemoryManager;
@@ -101,7 +101,7 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
@DependentService
protected DBTraceEquateManager equateManager;
@DependentService
- protected DBTraceLanguageManager languageManager;
+ protected DBTracePlatformManager platformManager;
@DependentService
protected DBTraceMemoryManager memoryManager;
@DependentService
@@ -283,12 +283,12 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
@DependentService
protected DBTraceCodeManager createCodeManager(DBTraceThreadManager threadManager,
- DBTraceLanguageManager languageManager, DBTraceDataTypeManager dataTypeManager,
+ DBTracePlatformManager platformManager, DBTraceDataTypeManager dataTypeManager,
DBTraceOverlaySpaceAdapter overlayAdapter, DBTraceReferenceManager referenceManager)
throws CancelledException, IOException {
return createTraceManager("Code Manager",
(openMode, monitor) -> new DBTraceCodeManager(dbh, openMode, rwLock, monitor,
- baseLanguage, this, threadManager, languageManager, dataTypeManager, overlayAdapter,
+ baseLanguage, this, threadManager, platformManager, dataTypeManager, overlayAdapter,
referenceManager));
}
@@ -325,11 +325,11 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
}
@DependentService
- protected DBTraceLanguageManager createLanguageManager()
+ protected DBTracePlatformManager createPlatformManager()
throws CancelledException, IOException {
return createTraceManager("Language Manager",
- (openMode, monitor) -> new DBTraceLanguageManager(dbh, openMode, rwLock, monitor,
- baseLanguage, this));
+ (openMode, monitor) -> new DBTracePlatformManager(dbh, openMode, rwLock, monitor,
+ baseCompilerSpec, this));
}
@DependentService
@@ -373,11 +373,11 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
@DependentService
protected DBTraceRegisterContextManager createRegisterContextManager(
- DBTraceThreadManager threadManager, DBTraceLanguageManager languageManager)
+ DBTraceThreadManager threadManager, DBTracePlatformManager platformManager)
throws CancelledException, IOException {
return createTraceManager("Context Manager",
(openMode, monitor) -> new DBTraceRegisterContextManager(dbh, openMode, rwLock, monitor,
- baseLanguage, this, threadManager, languageManager));
+ baseLanguage, this, threadManager, platformManager));
}
@DependentService
@@ -497,8 +497,8 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
}
@Override
- public DBTraceLanguageManager getLanguageManager() {
- return languageManager;
+ public DBTracePlatformManager getPlatformManager() {
+ return platformManager;
}
@Override
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTraceUtils.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTraceUtils.java
index 2fdbfd661d..980bcf8cc8 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTraceUtils.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTraceUtils.java
@@ -29,6 +29,7 @@ import com.google.common.collect.*;
import db.*;
import ghidra.program.model.address.*;
+import ghidra.program.model.lang.CompilerSpecID;
import ghidra.program.model.lang.LanguageID;
import ghidra.program.model.symbol.RefType;
import ghidra.program.model.symbol.RefTypeFactory;
@@ -161,6 +162,43 @@ public enum DBTraceUtils {
}
}
+ public static class CompilerSpecIDDBFieldCodec
+ extends AbstractDBFieldCodec {
+
+ public CompilerSpecIDDBFieldCodec(Class objectType, Field field, int column) {
+ super(CompilerSpecID.class, objectType, StringField.class, field, column);
+ }
+
+ @Override
+ public void store(CompilerSpecID value, StringField f) {
+ f.setString(value == null ? null : value.getIdAsString());
+ }
+
+ @Override
+ protected void doStore(OT obj, DBRecord record)
+ throws IllegalArgumentException, IllegalAccessException {
+ CompilerSpecID id = getValue(obj);
+ if (id == null) {
+ record.setString(column, null);
+ }
+ else {
+ record.setString(column, id.getIdAsString());
+ }
+ }
+
+ @Override
+ protected void doLoad(OT obj, DBRecord record)
+ throws IllegalArgumentException, IllegalAccessException {
+ String id = record.getString(column);
+ if (id == null) {
+ setValue(obj, null);
+ }
+ else {
+ setValue(obj, new CompilerSpecID(id));
+ }
+ }
+ }
+
public abstract static class AbstractOffsetSnapDBFieldCodec
extends AbstractDBFieldCodec {
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/context/DBTraceRegisterContextManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/context/DBTraceRegisterContextManager.java
index 428e96267d..32fcb289e6 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/context/DBTraceRegisterContextManager.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/context/DBTraceRegisterContextManager.java
@@ -31,7 +31,7 @@ import ghidra.program.model.lang.*;
import ghidra.program.model.listing.ProgramContext;
import ghidra.program.util.ProgramContextImpl;
import ghidra.trace.database.DBTrace;
-import ghidra.trace.database.language.DBTraceLanguageManager;
+import ghidra.trace.database.guest.DBTracePlatformManager;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData;
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager;
@@ -83,13 +83,13 @@ public class DBTraceRegisterContextManager extends
}
}
- protected final DBTraceLanguageManager languageManager;
+ protected final DBTracePlatformManager languageManager;
protected final Map defaultContexts = new HashMap<>();
public DBTraceRegisterContextManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock,
TaskMonitor monitor, Language baseLanguage, DBTrace trace,
- DBTraceThreadManager threadManager, DBTraceLanguageManager languageManager)
+ DBTraceThreadManager threadManager, DBTracePlatformManager languageManager)
throws VersionException, IOException {
super(NAME, dbh, openMode, lock, monitor, baseLanguage, trace, threadManager);
this.languageManager = languageManager;
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/context/DBTraceRegisterContextSpace.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/context/DBTraceRegisterContextSpace.java
index 6fe1b74a13..575c3aba71 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/context/DBTraceRegisterContextSpace.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/context/DBTraceRegisterContextSpace.java
@@ -32,6 +32,7 @@ import ghidra.program.model.lang.*;
import ghidra.trace.database.DBTrace;
import ghidra.trace.database.DBTraceUtils;
import ghidra.trace.database.context.DBTraceRegisterContextManager.DBTraceRegisterContextEntry;
+import ghidra.trace.database.guest.DBTraceGuestPlatform.DBTraceGuestLanguage;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapAddressSetView;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapSpace;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
@@ -70,8 +71,8 @@ public class DBTraceRegisterContextSpace implements TraceRegisterContextSpace, D
super(store, record);
}
- void set(int langKey, Register register) {
- this.langKey = langKey;
+ void set(DBTraceGuestLanguage guest, Register register) {
+ this.langKey = (int) (guest == null ? -1 : guest.getKey());
this.register = register.getName();
update(LANGUAGE_COLUMN, REGISTER_COLUMN);
}
@@ -110,7 +111,8 @@ public class DBTraceRegisterContextSpace implements TraceRegisterContextSpace, D
protected void loadRegisterValueMaps() throws VersionException {
for (DBTraceRegisterEntry ent : registerStore.asMap().values()) {
- Language language = manager.languageManager.getLanguageByKey(ent.langKey);
+ DBTraceGuestLanguage guest = manager.languageManager.getLanguageByKey(ent.langKey);
+ Language language = guest == null ? manager.getBaseLanguage() : guest.getLanguage();
Register register = language.getRegister(ent.register);
ImmutablePair pair = new ImmutablePair<>(language, register);
if (ent.map == null) {
@@ -161,12 +163,12 @@ public class DBTraceRegisterContextSpace implements TraceRegisterContextSpace, D
protected DBTraceAddressSnapRangePropertyMapSpace getRegisterValueMap(
Language language, Register register, boolean createIfAbsent) {
ImmutablePair pair = new ImmutablePair<>(language, register);
- int langKey = manager.languageManager.getKeyForLanguage(language);
+ DBTraceGuestLanguage guest = manager.languageManager.getLanguageByLanguage(language);
if (createIfAbsent) {
return registerValueMaps.computeIfAbsent(pair, t -> {
try {
DBTraceRegisterEntry ent = registerStore.create();
- ent.set(langKey, register);
+ ent.set(guest, register);
return createRegisterValueMap(t);
}
catch (VersionException e) {
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/language/DBTraceGuestLanguage.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTraceGuestPlatform.java
similarity index 54%
rename from Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/language/DBTraceGuestLanguage.java
rename to Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTraceGuestPlatform.java
index 70ee216a31..338a05cbcf 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/language/DBTraceGuestLanguage.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTraceGuestPlatform.java
@@ -13,8 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.trace.database.language;
+package ghidra.trace.database.guest;
+import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;
@@ -22,13 +23,17 @@ import com.google.common.collect.Range;
import db.DBRecord;
import ghidra.app.util.PseudoInstruction;
+import ghidra.lifecycle.Internal;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.Instruction;
import ghidra.program.model.mem.DumbMemBufferImpl;
import ghidra.program.model.mem.MemBuffer;
+import ghidra.program.util.DefaultLanguageService;
+import ghidra.trace.database.DBTraceUtils.CompilerSpecIDDBFieldCodec;
import ghidra.trace.database.DBTraceUtils.LanguageIDDBFieldCodec;
-import ghidra.trace.model.language.TraceGuestLanguage;
+import ghidra.trace.model.Trace;
+import ghidra.trace.model.guest.TraceGuestPlatform;
import ghidra.util.LockHold;
import ghidra.util.database.*;
import ghidra.util.database.annot.*;
@@ -37,59 +42,129 @@ import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
@DBAnnotatedObjectInfo(version = 0)
-public class DBTraceGuestLanguage extends DBAnnotatedObject implements TraceGuestLanguage {
- public static final String TABLE_NAME = "Languages";
+public class DBTraceGuestPlatform extends DBAnnotatedObject implements TraceGuestPlatform {
+ public static final String TABLE_NAME = "Platforms";
- static final String LANGID_COLUMN_NAME = "ID";
- static final String VERSION_COLUMN_NAME = "Version";
- static final String MINOR_VERSION_COLUMN_NAME = "MinorVersion";
+ @DBAnnotatedObjectInfo(version = 0)
+ public static class DBTraceGuestLanguage extends DBAnnotatedObject {
+ public static final String TABLE_NAME = "Languages";
- @DBAnnotatedColumn(LANGID_COLUMN_NAME)
- static DBObjectColumn LANGID_COLUMN;
- @DBAnnotatedColumn(VERSION_COLUMN_NAME)
- static DBObjectColumn VERSION_COLUMN;
- @DBAnnotatedColumn(MINOR_VERSION_COLUMN_NAME)
- static DBObjectColumn MINOR_VERSION_COLUMN;
+ static final String LANGID_COLUMN_NAME = "Lang";
+ static final String VERSION_COLUMN_NAME = "Version";
+ static final String MINOR_VERSION_COLUMN_NAME = "MinorVersion";
- @DBAnnotatedField(column = LANGID_COLUMN_NAME, codec = LanguageIDDBFieldCodec.class)
- private LanguageID langID;
- @DBAnnotatedField(column = VERSION_COLUMN_NAME)
- private int version;
- @DBAnnotatedField(column = MINOR_VERSION_COLUMN_NAME)
- private int minorVersion;
+ @DBAnnotatedColumn(LANGID_COLUMN_NAME)
+ static DBObjectColumn LANGID_COLUMN;
+ @DBAnnotatedColumn(VERSION_COLUMN_NAME)
+ static DBObjectColumn VERSION_COLUMN;
+ @DBAnnotatedColumn(MINOR_VERSION_COLUMN_NAME)
+ static DBObjectColumn MINOR_VERSION_COLUMN;
- private final DBTraceLanguageManager manager;
+ @DBAnnotatedField(column = LANGID_COLUMN_NAME, codec = LanguageIDDBFieldCodec.class)
+ private LanguageID langID;
+ @DBAnnotatedField(column = VERSION_COLUMN_NAME)
+ private int version;
+ @DBAnnotatedField(column = MINOR_VERSION_COLUMN_NAME)
+ private int minorVersion;
- private Language guestLanguage;
+ private Language language;
- protected final NavigableMap rangesByHostAddress =
+ public DBTraceGuestLanguage(DBCachedObjectStore> store, DBRecord record) {
+ super(store, record);
+ }
+
+ @Override
+ protected void fresh(boolean created) throws IOException {
+ super.fresh(created);
+ if (created) {
+ return;
+ }
+ LanguageService langServ = DefaultLanguageService.getLanguageService();
+ language = langServ.getLanguage(langID);
+ if (version != language.getVersion() || minorVersion != language.getMinorVersion()) {
+ throw new IOException(new VersionException()); // TODO Upgrade
+ }
+ }
+
+ void set(Language language) {
+ this.langID = language.getLanguageID();
+ this.version = language.getVersion();
+ this.minorVersion = language.getMinorVersion();
+ update(LANGID_COLUMN, VERSION_COLUMN, MINOR_VERSION_COLUMN);
+ this.language = language;
+ }
+
+ public Language getLanguage() {
+ return language;
+ }
+ }
+
+ static final String LANGKEY_COLUMN_NAME = "Lang";
+ static final String CSPECID_COLUMN_NAME = "CSpec";
+
+ @DBAnnotatedColumn(LANGKEY_COLUMN_NAME)
+ static DBObjectColumn LANGKEY_COLUMN;
+ @DBAnnotatedColumn(CSPECID_COLUMN_NAME)
+ static DBObjectColumn CSPECID_COLUMN;
+
+ @DBAnnotatedField(column = LANGKEY_COLUMN_NAME)
+ private int langKey;
+ @DBAnnotatedField(column = CSPECID_COLUMN_NAME, codec = CompilerSpecIDDBFieldCodec.class)
+ private CompilerSpecID cSpecID;
+
+ private DBTraceGuestLanguage languageEntry;
+ private CompilerSpec compilerSpec;
+
+ final DBTracePlatformManager manager;
+ protected final NavigableMap rangesByHostAddress =
new TreeMap<>();
protected final AddressSet hostAddressSet = new AddressSet();
- protected final NavigableMap rangesByGuestAddress =
+ protected final NavigableMap rangesByGuestAddress =
new TreeMap<>();
protected final AddressSet guestAddressSet = new AddressSet();
- public DBTraceGuestLanguage(DBTraceLanguageManager manager, DBCachedObjectStore> store,
+ public DBTraceGuestPlatform(DBTracePlatformManager manager, DBCachedObjectStore> store,
DBRecord record) {
super(store, record);
this.manager = manager;
}
- void setLanguage(Language language) {
- this.guestLanguage = language;
- this.langID = language.getLanguageID();
- this.version = language.getVersion();
- this.minorVersion = language.getMinorVersion();
- update(LANGID_COLUMN, VERSION_COLUMN, MINOR_VERSION_COLUMN);
+ void set(CompilerSpec compilerSpec) {
+ this.languageEntry = manager.getOrCreateLanguage(compilerSpec.getLanguage());
+ this.langKey = (int) (languageEntry == null ? -1 : languageEntry.getKey());
+ this.cSpecID = compilerSpec.getCompilerSpecID();
+ update(LANGKEY_COLUMN, CSPECID_COLUMN);
+ this.compilerSpec = compilerSpec;
}
- protected void deleteMappedRange(DBTraceGuestLanguageMappedRange range, TaskMonitor monitor)
+ @Override
+ protected void fresh(boolean created) throws IOException {
+ super.fresh(created);
+ if (created) {
+ return;
+ }
+ this.languageEntry = manager.getLanguageByKey(langKey);
+ if (languageEntry == null && langKey != -1) {
+ throw new IOException("Platform table is corrupt. Missing language " + langKey);
+ }
+ compilerSpec = getLanguage().getCompilerSpecByID(cSpecID);
+ if (compilerSpec == null) {
+ throw new IOException(
+ "Platform table is corrupt. Invalid compiler spec " + compilerSpec);
+ }
+ }
+
+ @Override
+ public Trace getTrace() {
+ return manager.trace;
+ }
+
+ protected void deleteMappedRange(DBTraceGuestPlatformMappedRange range, TaskMonitor monitor)
throws CancelledException {
try (LockHold hold = LockHold.lock(manager.lock.writeLock())) {
manager.trace.getCodeManager()
- .clearLanguage(Range.all(), range.getHostRange(),
- (int) getKey(), monitor);
+ .clearPlatform(Range.all(), range.getHostRange(), this, monitor);
manager.rangeMappingStore.delete(range);
AddressRange hostRange = range.getHostRange();
AddressRange guestRange = range.getGuestRange();
@@ -100,41 +175,43 @@ public class DBTraceGuestLanguage extends DBAnnotatedObject implements TraceGues
}
}
- protected void doGetLanguage(LanguageService langServ)
- throws LanguageNotFoundException, VersionException {
- this.guestLanguage = langServ.getLanguage(langID);
- if (version != guestLanguage.getVersion() ||
- minorVersion != guestLanguage.getMinorVersion()) {
- throw new VersionException(); // TODO Upgrade
- }
+ @Internal
+ public DBTraceGuestLanguage getLanguageEntry() {
+ return languageEntry;
}
@Override
public Language getLanguage() {
- return guestLanguage;
+ return languageEntry == null ? manager.baseLanguage : languageEntry.getLanguage();
+ }
+
+ @Override
+ public CompilerSpec getCompilerSpec() {
+ return compilerSpec;
}
@Override
public void delete(TaskMonitor monitor) throws CancelledException {
- manager.deleteGuestLanguage(this, monitor);
+ manager.deleteGuestPlatform(this, monitor);
+ // TODO: Delete language once no platform uses it?
}
@Override
- public DBTraceGuestLanguageMappedRange addMappedRange(Address hostStart, Address guestStart,
+ public DBTraceGuestPlatformMappedRange addMappedRange(Address hostStart, Address guestStart,
long length) throws AddressOverflowException {
try (LockHold hold = LockHold.lock(manager.lock.writeLock())) {
- Address hostEnd = hostStart.addNoWrap(length - 1);
+ Address hostEnd = hostStart.addWrap(length - 1);
if (hostAddressSet.intersects(hostStart, hostEnd)) {
// TODO: Check for compatibility and extend?
throw new IllegalArgumentException(
"Range overlaps existing host mapped range(s) for this guest language");
}
- Address guestEnd = guestStart.addNoWrap(length - 1);
+ Address guestEnd = guestStart.addWrap(length - 1);
if (guestAddressSet.intersects(guestStart, guestEnd)) {
throw new IllegalArgumentException("Range overlaps existing guest mapped range(s)");
}
- DBTraceGuestLanguageMappedRange mappedRange = manager.rangeMappingStore.create();
- mappedRange.set(hostStart, guestLanguage, guestStart, length);
+ DBTraceGuestPlatformMappedRange mappedRange = manager.rangeMappingStore.create();
+ mappedRange.set(hostStart, this, guestStart, length);
rangesByHostAddress.put(hostStart, mappedRange);
rangesByGuestAddress.put(guestStart, mappedRange);
hostAddressSet.add(mappedRange.getHostRange());
@@ -156,7 +233,7 @@ public class DBTraceGuestLanguage extends DBAnnotatedObject implements TraceGues
@Override
public Address mapHostToGuest(Address hostAddress) {
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
- Entry floorEntry =
+ Entry floorEntry =
rangesByHostAddress.floorEntry(hostAddress);
if (floorEntry == null) {
return null;
@@ -168,7 +245,7 @@ public class DBTraceGuestLanguage extends DBAnnotatedObject implements TraceGues
@Override
public Address mapGuestToHost(Address guestAddress) {
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
- Entry floorEntry =
+ Entry floorEntry =
rangesByGuestAddress.floorEntry(guestAddress);
if (floorEntry == null) {
return null;
@@ -186,12 +263,12 @@ public class DBTraceGuestLanguage extends DBAnnotatedObject implements TraceGues
*/
public Address mapGuestToHost(Address guestMin, Address guestMax) {
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
- Entry floorEntry =
+ Entry floorEntry =
rangesByGuestAddress.floorEntry(guestMin);
if (floorEntry == null) {
return null;
}
- DBTraceGuestLanguageMappedRange range = floorEntry.getValue();
+ DBTraceGuestPlatformMappedRange range = floorEntry.getValue();
if (!range.getGuestRange().contains(guestMax)) {
return null;
}
@@ -204,7 +281,7 @@ public class DBTraceGuestLanguage extends DBAnnotatedObject implements TraceGues
/*return new DBTraceGuestLanguageMappedMemBuffer(manager.trace.getMemoryManager(), this, snap,
guestAddress);*/
return new DumbMemBufferImpl(
- new DBTraceGuestLanguageMappedMemory(manager.trace.getMemoryManager(), this, snap),
+ new DBTraceGuestPlatformMappedMemory(manager.trace.getMemoryManager(), this, snap),
guestAddress);
}
@@ -212,7 +289,7 @@ public class DBTraceGuestLanguage extends DBAnnotatedObject implements TraceGues
public InstructionSet mapGuestInstructionAddressesToHost(InstructionSet instructionSet) {
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
Map blocksByNext = new HashMap<>();
- InstructionSet mappedSet = new InstructionSet(guestLanguage.getAddressFactory());
+ InstructionSet mappedSet = new InstructionSet(getAddressFactory());
for (InstructionBlock block : instructionSet) {
for (Instruction instruction : block) {
Address hostAddr =
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/language/DBTraceGuestLanguageMappedMemory.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTraceGuestPlatformMappedMemory.java
similarity index 96%
rename from Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/language/DBTraceGuestLanguageMappedMemory.java
rename to Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTraceGuestPlatformMappedMemory.java
index 3d305012ee..7ca211644b 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/language/DBTraceGuestLanguageMappedMemory.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTraceGuestPlatformMappedMemory.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.trace.database.language;
+package ghidra.trace.database.guest;
import static ghidra.lifecycle.Unfinished.TODO;
@@ -32,6 +32,7 @@ import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.*;
import ghidra.trace.database.memory.DBTraceMemoryManager;
import ghidra.trace.database.memory.DBTraceMemorySpace;
+import ghidra.util.MathUtilities;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.NotFoundException;
import ghidra.util.task.TaskMonitor;
@@ -39,15 +40,16 @@ import ghidra.util.task.TaskMonitor;
/**
* TODO: Document me
*
+ *
* Note this is the bare minimum to support {@link DumbMemBufferImpl}
*/
-public class DBTraceGuestLanguageMappedMemory implements Memory {
+public class DBTraceGuestPlatformMappedMemory implements Memory {
protected final DBTraceMemoryManager manager;
- protected final DBTraceGuestLanguage guest;
+ protected final DBTraceGuestPlatform guest;
protected final long snap;
- public DBTraceGuestLanguageMappedMemory(DBTraceMemoryManager manager,
- DBTraceGuestLanguage guest, long snap) {
+ public DBTraceGuestPlatformMappedMemory(DBTraceMemoryManager manager,
+ DBTraceGuestPlatform guest, long snap) {
this.manager = manager;
this.guest = guest;
this.snap = snap;
@@ -358,17 +360,17 @@ public class DBTraceGuestLanguageMappedMemory implements Memory {
while (buffer.hasRemaining()) {
int offset = buffer.position() - startPos;
Address guestCur = guestStart.add(offset);
- Entry
floorEntry =
+ Entry floorEntry =
guest.rangesByGuestAddress.floorEntry(guestCur);
if (floorEntry == null) {
return offset;
}
- DBTraceGuestLanguageMappedRange range = floorEntry.getValue();
+ DBTraceGuestPlatformMappedRange range = floorEntry.getValue();
Address hostCur = range.mapGuestToHost(guestCur);
if (hostCur == null) {
return offset;
}
- int lenToRead = (int) Math.min(buffer.remaining(),
+ int lenToRead = MathUtilities.unsignedMin(buffer.remaining(),
range.getGuestRange().getMaxAddress().subtract(guestStart) + 1);
DBTraceMemorySpace hostSpace = manager.getMemorySpace(hostCur.getAddressSpace(), false);
if (hostSpace == null) {
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/language/DBTraceGuestLanguageMappedRange.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTraceGuestPlatformMappedRange.java
similarity index 80%
rename from Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/language/DBTraceGuestLanguageMappedRange.java
rename to Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTraceGuestPlatformMappedRange.java
index 2386b499c4..a53565f040 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/language/DBTraceGuestLanguageMappedRange.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTraceGuestPlatformMappedRange.java
@@ -13,22 +13,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.trace.database.language;
+package ghidra.trace.database.guest;
import java.io.IOException;
import db.DBRecord;
import ghidra.program.model.address.*;
+import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.lang.Language;
-import ghidra.trace.model.language.TraceGuestLanguageMappedRange;
+import ghidra.trace.model.guest.TraceGuestPlatformMappedRange;
import ghidra.util.database.*;
import ghidra.util.database.annot.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
@DBAnnotatedObjectInfo(version = 0)
-public class DBTraceGuestLanguageMappedRange extends DBAnnotatedObject
- implements TraceGuestLanguageMappedRange {
+public class DBTraceGuestPlatformMappedRange extends DBAnnotatedObject
+ implements TraceGuestPlatformMappedRange {
public static final String TABLE_NAME = "LanguageMappings";
static final String HOST_SPACE_COLUMN_NAME = "HostSpace";
@@ -56,7 +57,7 @@ public class DBTraceGuestLanguageMappedRange extends DBAnnotatedObject
@DBAnnotatedField(column = HOST_OFFSET_COLUMN_NAME)
private long hostOffset;
@DBAnnotatedField(column = GUEST_LANGUAGE_COLUMN_NAME)
- int guestLangKey;
+ int guestPlatformKey;
@DBAnnotatedField(column = GUEST_SPACE_COLUMN_NAME)
private int guestSpace;
@DBAnnotatedField(column = GUEST_OFFSET_COLUMN_NAME)
@@ -64,13 +65,13 @@ public class DBTraceGuestLanguageMappedRange extends DBAnnotatedObject
@DBAnnotatedField(column = LENGTH_COLUMN_NAME)
private long length;
- private DBTraceLanguageManager manager;
+ private DBTracePlatformManager manager;
private AddressRangeImpl hostRange;
- private Language guestLanguage;
+ private DBTraceGuestPlatform guestPlatform;
private AddressRangeImpl guestRange;
- public DBTraceGuestLanguageMappedRange(DBTraceLanguageManager manager, DBCachedObjectStore> s,
+ public DBTraceGuestPlatformMappedRange(DBTracePlatformManager manager, DBCachedObjectStore> s,
DBRecord r) {
super(s, r);
this.manager = manager;
@@ -88,9 +89,9 @@ public class DBTraceGuestLanguageMappedRange extends DBAnnotatedObject
Address hostEnd = hostStart.addNoWrap(length - 1);
this.hostRange = new AddressRangeImpl(hostStart, hostEnd);
- this.guestLanguage = manager.getLanguageByKey(guestLangKey);
+ this.guestPlatform = manager.getPlatformByKey(guestPlatformKey);
Address guestStart =
- guestLanguage.getAddressFactory().getAddress(guestSpace, guestOffset);
+ guestPlatform.getAddressFactory().getAddress(guestSpace, guestOffset);
Address guestEnd = guestStart.addNoWrap(length - 1);
this.guestRange = new AddressRangeImpl(guestStart, guestEnd);
}
@@ -99,19 +100,21 @@ public class DBTraceGuestLanguageMappedRange extends DBAnnotatedObject
}
}
- void set(Address hostStart, Language guestLanguage, Address guestStart, long length) {
- this.hostRange = new AddressRangeImpl(hostStart, hostStart.add(length - 1));
- this.guestLanguage = guestLanguage;
- this.guestRange = new AddressRangeImpl(guestStart, guestStart.add(length - 1));
-
+ void set(Address hostStart, DBTraceGuestPlatform guestPlatform, Address guestStart,
+ long length) {
this.hostSpace = hostStart.getAddressSpace().getSpaceID();
this.hostOffset = hostStart.getOffset();
- this.guestLangKey = manager.getKeyForLanguage(guestLanguage);
+ this.guestPlatformKey = (int) guestPlatform.getKey();
this.guestSpace = guestStart.getAddressSpace().getSpaceID();
this.guestOffset = guestStart.getOffset();
this.length = length;
update(HOST_SPACE_COLUMN, HOST_OFFSET_COLUMN, GUEST_LANGUAGE_COLUMN, GUEST_SPACE_COLUMN,
GUEST_OFFSET_COLUMN, LENGTH_COLUMN);
+
+ this.hostRange = new AddressRangeImpl(hostStart, hostStart.addWrap(length - 1));
+ this.guestPlatform = guestPlatform;
+ this.guestRange = new AddressRangeImpl(guestStart, guestStart.addWrap(length - 1));
+
}
@Override
@@ -119,14 +122,19 @@ public class DBTraceGuestLanguageMappedRange extends DBAnnotatedObject
return manager.getBaseLanguage();
}
+ @Override
+ public CompilerSpec getHostCompilerSpec() {
+ return manager.getBaseCompilerSpec();
+ }
+
@Override
public AddressRange getHostRange() {
return hostRange;
}
@Override
- public Language getGuestLanguage() {
- return guestLanguage;
+ public DBTraceGuestPlatform getGuestPlatform() {
+ return guestPlatform;
}
@Override
@@ -154,6 +162,6 @@ public class DBTraceGuestLanguageMappedRange extends DBAnnotatedObject
@Override
public void delete(TaskMonitor monitor) throws CancelledException {
- manager.languageStore.getObjectAt(guestLangKey).deleteMappedRange(this, monitor);
+ manager.platformStore.getObjectAt(guestPlatformKey).deleteMappedRange(this, monitor);
}
}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTracePlatformManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTracePlatformManager.java
new file mode 100644
index 0000000000..005cb4a078
--- /dev/null
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTracePlatformManager.java
@@ -0,0 +1,298 @@
+/* ###
+ * 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.guest;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.locks.ReadWriteLock;
+
+import db.DBHandle;
+import ghidra.lifecycle.Internal;
+import ghidra.program.model.lang.*;
+import ghidra.program.model.listing.Instruction;
+import ghidra.trace.database.DBTrace;
+import ghidra.trace.database.DBTraceManager;
+import ghidra.trace.database.guest.DBTraceGuestPlatform.DBTraceGuestLanguage;
+import ghidra.trace.model.guest.TraceGuestPlatform;
+import ghidra.trace.model.guest.TracePlatformManager;
+import ghidra.trace.model.listing.TraceInstruction;
+import ghidra.util.LockHold;
+import ghidra.util.database.*;
+import ghidra.util.exception.CancelledException;
+import ghidra.util.exception.VersionException;
+import ghidra.util.task.TaskMonitor;
+
+/*
+ * TODO: Store mapping as from (host) address, to (guest) address, length. "to" must include
+ * spaceId. It is not a problem if things overlap, as these are just informational in case an
+ * instruction or reference comes along that needs mapping. This also determines what is visible
+ * in program views of the mapped language. There should not be any overlaps in the same guest
+ * language, however.
+ */
+public class DBTracePlatformManager implements DBTraceManager, TracePlatformManager {
+ protected final DBHandle dbh;
+ protected final ReadWriteLock lock;
+ protected final Language baseLanguage;
+ protected final CompilerSpec baseCompilerSpec;
+ protected final DBTrace trace;
+
+ protected final DBCachedObjectStore languageStore;
+ protected final DBCachedObjectStore platformStore;
+ protected final Collection platformView;
+ protected final Map languagesByLanguage = new HashMap<>();
+ protected final Map platformsByCompiler = new HashMap<>();
+
+ protected final DBCachedObjectStore rangeMappingStore;
+
+ public DBTracePlatformManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock,
+ TaskMonitor monitor, CompilerSpec baseCompilerSpec, DBTrace trace)
+ throws VersionException, IOException {
+ this.dbh = dbh;
+ this.lock = lock;
+ this.baseLanguage = baseCompilerSpec.getLanguage();
+ this.baseCompilerSpec = baseCompilerSpec;
+ this.trace = trace;
+
+ DBCachedObjectStoreFactory factory = trace.getStoreFactory();
+ languageStore = factory.getOrCreateCachedStore(DBTraceGuestLanguage.TABLE_NAME,
+ DBTraceGuestLanguage.class, DBTraceGuestLanguage::new, true);
+ platformStore = factory.getOrCreateCachedStore(DBTraceGuestPlatform.TABLE_NAME,
+ DBTraceGuestPlatform.class, (s, r) -> new DBTraceGuestPlatform(this, s, r), true);
+ platformView = Collections.unmodifiableCollection(platformStore.asMap().values());
+
+ rangeMappingStore = factory.getOrCreateCachedStore(
+ DBTraceGuestPlatformMappedRange.TABLE_NAME, DBTraceGuestPlatformMappedRange.class,
+ (s, r) -> new DBTraceGuestPlatformMappedRange(this, s, r), true);
+
+ loadLanguages();
+ loadPlatforms();
+ loadPlatformMappings();
+ }
+
+ protected void loadLanguages() {
+ for (DBTraceGuestLanguage languageEntry : languageStore.asMap().values()) {
+ languagesByLanguage.put(languageEntry.getLanguage(), languageEntry);
+ }
+ }
+
+ protected void loadPlatforms()
+ throws LanguageNotFoundException, CompilerSpecNotFoundException, VersionException {
+ for (DBTraceGuestPlatform platformEntry : platformStore.asMap().values()) {
+ platformsByCompiler.put(platformEntry.getCompilerSpec(), platformEntry);
+ }
+ }
+
+ protected void loadPlatformMappings() {
+ for (DBTraceGuestPlatformMappedRange langMapping : rangeMappingStore.asMap().values()) {
+ DBTraceGuestPlatform mappedLanguage =
+ platformStore.getObjectAt(langMapping.guestPlatformKey);
+ mappedLanguage.rangesByHostAddress.put(langMapping.getHostRange().getMinAddress(),
+ langMapping);
+ mappedLanguage.rangesByGuestAddress.put(langMapping.getGuestRange().getMinAddress(),
+ langMapping);
+ }
+ }
+
+ @Internal
+ protected DBTraceGuestLanguage getOrCreateLanguage(Language language) {
+ if (language == baseLanguage) {
+ return null;
+ }
+ DBTraceGuestLanguage languageEntry = languagesByLanguage.get(language);
+ if (languageEntry == null) {
+ languageEntry = languageStore.create();
+ languageEntry.set(language);
+ languagesByLanguage.put(language, languageEntry);
+ }
+ return languageEntry;
+ }
+
+ @Internal
+ public DBTraceGuestLanguage getLanguageByKey(int key) {
+ if (key == -1) {
+ return null;
+ }
+ return languageStore.getObjectAt(key);
+ }
+
+ @Internal
+ public DBTraceGuestPlatform getPlatformByKey(int key) {
+ if (key == -1) {
+ return null;
+ }
+ return platformStore.getObjectAt(key);
+ }
+
+ protected int getPlatformKeyForCompiler(CompilerSpec compiler) {
+ if (Objects.equals(compiler, baseCompilerSpec)) {
+ return -1;
+ }
+ return (int) platformsByCompiler.get(compiler).getKey();
+ }
+
+ @Internal
+ public DBTraceGuestLanguage getLanguageByLanguage(Language language) {
+ if (Objects.equals(language, baseLanguage)) {
+ return null;
+ }
+ return Objects.requireNonNull(languagesByLanguage.get(language));
+ }
+
+ protected CompilerSpec getCompilerByKey(int compilerKey) {
+ if (compilerKey == -1) {
+ return baseCompilerSpec;
+ }
+ return platformStore.getObjectAt(compilerKey).getCompilerSpec();
+ }
+
+ @Override
+ public void dbError(IOException e) {
+ trace.dbError(e);
+ }
+
+ @Override
+ public void invalidateCache(boolean all) {
+ languageStore.invalidateCache();
+ platformStore.invalidateCache();
+ rangeMappingStore.invalidateCache();
+ languagesByLanguage.clear();
+ platformsByCompiler.clear();
+ try {
+ loadLanguages();
+ loadPlatforms();
+ loadPlatformMappings();
+ }
+ catch (LanguageNotFoundException | CompilerSpecNotFoundException | VersionException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ protected void deleteGuestPlatform(DBTraceGuestPlatform platform, TaskMonitor monitor)
+ throws CancelledException {
+ try (LockHold hold = LockHold.lock(lock.writeLock())) {
+ int platformKey = (int) platform.getKey();
+ trace.getCodeManager().deletePlatform(platform, monitor);
+ monitor.setMessage("Clearing guest platform range mappings");
+ monitor.setMaximum(rangeMappingStore.getRecordCount());
+ for (Iterator it =
+ rangeMappingStore.asMap().values().iterator(); it.hasNext();) {
+ DBTraceGuestPlatformMappedRange range = it.next();
+ if (platformKey != range.guestPlatformKey) {
+ continue;
+ }
+ it.remove();
+ }
+ platformsByCompiler.remove(platform.getCompilerSpec());
+ platformStore.delete(platform);
+ }
+ }
+
+ @Override
+ public Language getBaseLanguage() {
+ return trace.getBaseLanguage();
+ }
+
+ @Override
+ public CompilerSpec getBaseCompilerSpec() {
+ return trace.getBaseCompilerSpec();
+ }
+
+ protected DBTraceGuestPlatform doAddGuestPlatform(CompilerSpec compilerSpec) {
+ DBTraceGuestPlatform platformEntry = platformStore.create();
+ platformEntry.set(compilerSpec);
+ platformsByCompiler.put(compilerSpec, platformEntry);
+ return platformEntry;
+ }
+
+ @Override
+ public DBTraceGuestPlatform addGuestPlatform(CompilerSpec compilerSpec) {
+ if (compilerSpec.getCompilerSpecID()
+ .equals(trace.getBaseCompilerSpec().getCompilerSpecID())) {
+ throw new IllegalArgumentException("Base language cannot be a guest language");
+ }
+ try (LockHold hold = LockHold.lock(lock.writeLock())) {
+ return doAddGuestPlatform(compilerSpec);
+ }
+ }
+
+ @Override
+ public DBTraceGuestPlatform getGuestPlatform(CompilerSpec compilerSpec) {
+ try (LockHold hold = LockHold.lock(lock.readLock())) {
+ return platformsByCompiler.get(compilerSpec);
+ }
+ }
+
+ @Override
+ public DBTraceGuestPlatform getOrAddGuestPlatform(CompilerSpec compilerSpec) {
+ if (compilerSpec.getCompilerSpecID()
+ .equals(trace.getBaseCompilerSpec().getCompilerSpecID())) {
+ throw new IllegalArgumentException("Base language cannot be a guest language");
+ }
+ try (LockHold hold = LockHold.lock(lock.writeLock())) {
+ DBTraceGuestPlatform exists = platformsByCompiler.get(compilerSpec);
+ if (exists != null) {
+ return exists;
+ }
+ return doAddGuestPlatform(compilerSpec);
+ }
+ }
+
+ @Override
+ public Collection getGuestPlatforms() {
+ return platformView;
+ }
+
+ protected TraceGuestPlatform getPlatformOf(InstructionSet instructionSet) {
+ for (InstructionBlock block : instructionSet) {
+ for (Instruction instruction : block) {
+ if (!(instruction instanceof TraceInstruction)) {
+ continue;
+ }
+ TraceInstruction traceInstruction = (TraceInstruction) instruction;
+ return traceInstruction.getGuestPlatform();
+ }
+ }
+ return null;
+ }
+
+ public InstructionSet mapGuestInstructionAddressesToHost(TraceGuestPlatform platform,
+ InstructionSet instructionSet) {
+ try (LockHold hold = LockHold.lock(lock.readLock())) {
+ if (platform == null) { // Instructions belong to the host platform
+ return instructionSet;
+ }
+ return platform.mapGuestInstructionAddressesToHost(instructionSet);
+ }
+ }
+
+ @Internal
+ public DBTraceGuestPlatform assertMine(TraceGuestPlatform platform) {
+ if (platform == null) {
+ return null;
+ }
+ if (!(platform instanceof DBTraceGuestPlatform)) {
+ throw new IllegalArgumentException("Given platform does not belong to this trace");
+ }
+ DBTraceGuestPlatform dbPlatform = (DBTraceGuestPlatform) platform;
+ if (dbPlatform.manager != this) {
+ throw new IllegalArgumentException("Given platform does not belong to this trace");
+ }
+ if (dbPlatform.isDeleted()) {
+ throw new IllegalArgumentException("Given platform has been deleted");
+ }
+ return dbPlatform;
+ }
+}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/language/DBTraceLanguageManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/language/DBTraceLanguageManager.java
deleted file mode 100644
index 2aa4d7fe6c..0000000000
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/language/DBTraceLanguageManager.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/* ###
- * 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.language;
-
-import java.io.IOException;
-import java.util.*;
-import java.util.concurrent.locks.ReadWriteLock;
-
-import db.DBHandle;
-import ghidra.program.model.lang.*;
-import ghidra.program.model.listing.Instruction;
-import ghidra.program.util.DefaultLanguageService;
-import ghidra.trace.database.DBTrace;
-import ghidra.trace.database.DBTraceManager;
-import ghidra.trace.model.language.TraceGuestLanguage;
-import ghidra.trace.model.language.TraceLanguageManager;
-import ghidra.util.LockHold;
-import ghidra.util.database.*;
-import ghidra.util.exception.CancelledException;
-import ghidra.util.exception.VersionException;
-import ghidra.util.task.TaskMonitor;
-
-/*
- * TODO: Store mapping as from (host) address, to (guest) address, length. "to" must include
- * spaceId. It is not a problem if things overlap, as these are just informational in case an
- * instruction or reference comes along that needs mapping. This also determines what is visible
- * in program views of the mapped language. There should not be any overlaps in the same guest
- * language, however.
- */
-public class DBTraceLanguageManager implements DBTraceManager, TraceLanguageManager {
- protected final DBHandle dbh;
- protected final ReadWriteLock lock;
- protected final Language baseLanguage;
- protected final DBTrace trace;
-
- protected final DBCachedObjectStore languageStore;
- protected final Collection languageView;
- protected final Map entriesByLanguage = new HashMap<>();
-
- protected final DBCachedObjectStore rangeMappingStore;
-
- public DBTraceLanguageManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock,
- TaskMonitor monitor, Language baseLanguage, DBTrace trace)
- throws VersionException, IOException {
- this.dbh = dbh;
- this.lock = lock;
- this.baseLanguage = baseLanguage;
- this.trace = trace;
-
- DBCachedObjectStoreFactory factory = trace.getStoreFactory();
- languageStore = factory.getOrCreateCachedStore(DBTraceGuestLanguage.TABLE_NAME,
- DBTraceGuestLanguage.class, (s, r) -> new DBTraceGuestLanguage(this, s, r), true);
- languageView = Collections.unmodifiableCollection(languageStore.asMap().values());
-
- rangeMappingStore = factory.getOrCreateCachedStore(
- DBTraceGuestLanguageMappedRange.TABLE_NAME, DBTraceGuestLanguageMappedRange.class,
- (s, r) -> new DBTraceGuestLanguageMappedRange(this, s, r), true);
-
- loadLanguages();
- loadLanguageMappings();
- }
-
- protected void loadLanguages() throws LanguageNotFoundException, VersionException {
- LanguageService langServ = DefaultLanguageService.getLanguageService();
- for (DBTraceGuestLanguage langEnt : languageStore.asMap().values()) {
- langEnt.doGetLanguage(langServ);
- entriesByLanguage.put(langEnt.getLanguage(), langEnt);
- }
- }
-
- protected void loadLanguageMappings() {
- for (DBTraceGuestLanguageMappedRange langMapping : rangeMappingStore.asMap().values()) {
- DBTraceGuestLanguage mappedLanguage =
- languageStore.getObjectAt(langMapping.guestLangKey);
- mappedLanguage.rangesByHostAddress.put(langMapping.getHostRange().getMinAddress(),
- langMapping);
- mappedLanguage.rangesByGuestAddress.put(langMapping.getGuestRange().getMinAddress(),
- langMapping);
- }
- }
-
- // Internal
- public int getKeyForLanguage(Language language) {
- if (Objects.equals(language, baseLanguage)) {
- return -1;
- }
- return (int) entriesByLanguage.get(language).getKey();
- }
-
- // Internal
- public Language getLanguageByKey(int langKey) {
- if (langKey == -1) {
- return baseLanguage;
- }
- return languageStore.getObjectAt(langKey).getLanguage();
- }
-
- @Override
- public void dbError(IOException e) {
- trace.dbError(e);
- }
-
- @Override
- public void invalidateCache(boolean all) {
- languageStore.invalidateCache();
- rangeMappingStore.invalidateCache();
- entriesByLanguage.clear();
- try {
- loadLanguages();
- loadLanguageMappings();
- }
- catch (LanguageNotFoundException | VersionException e) {
- throw new AssertionError(e);
- }
- }
-
- protected void deleteGuestLanguage(DBTraceGuestLanguage langEnt, TaskMonitor monitor)
- throws CancelledException {
- try (LockHold hold = LockHold.lock(lock.writeLock())) {
- int langKey = (int) langEnt.getKey();
- trace.getCodeManager().deleteLanguage(langKey, monitor);
- monitor.setMessage("Clearing guest language range mappings");
- monitor.setMaximum(rangeMappingStore.getRecordCount());
- for (Iterator it =
- rangeMappingStore.asMap().values().iterator(); it.hasNext();) {
- DBTraceGuestLanguageMappedRange range = it.next();
- if (langKey != range.guestLangKey) {
- continue;
- }
- it.remove();
- }
- entriesByLanguage.remove(langEnt.getLanguage());
- languageStore.delete(langEnt);
- }
- }
-
- @Override
- public Language getBaseLanguage() {
- return trace.getBaseLanguage();
- }
-
- @Override
- public DBTraceGuestLanguage addGuestLanguage(Language language) {
- if (language.getLanguageID().equals(trace.getBaseLanguage().getLanguageID())) {
- throw new IllegalArgumentException("Base language cannot be a guest language");
- }
- try (LockHold hold = LockHold.lock(lock.writeLock())) {
- DBTraceGuestLanguage langEnt = languageStore.create();
- langEnt.setLanguage(language);
- entriesByLanguage.put(language, langEnt);
- return langEnt;
- }
- }
-
- public DBTraceGuestLanguage getGuestLanguage(Language language) {
- try (LockHold hold = LockHold.lock(lock.readLock())) {
- return entriesByLanguage.get(language);
- }
- }
-
- @Override
- public Collection getGuestLanguages() {
- return languageView;
- }
-
- protected Language getLanguageOf(InstructionSet instructionSet) {
- for (InstructionBlock block : instructionSet) {
- for (Instruction instruction : block) {
- return instruction.getPrototype().getLanguage();
- }
- }
- // No instructions, default to base language
- return trace.getBaseLanguage();
- }
-
- @Override
- public InstructionSet mapGuestInstructionAddressesToHost(InstructionSet instructionSet) {
- try (LockHold hold = LockHold.lock(lock.readLock())) {
- Language language = getLanguageOf(instructionSet);
- if (language == trace.getBaseLanguage()) {
- return instructionSet; // Nothing to map
- }
- DBTraceGuestLanguage guest = trace.getLanguageManager().getGuestLanguage(language);
- if (guest == null) {
- throw new IllegalArgumentException(
- "Instructions are in neither the base nor a guest language");
- }
- return guest.mapGuestInstructionAddressesToHost(instructionSet);
- }
- }
-}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/AbstractDBTraceDataComponent.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/AbstractDBTraceDataComponent.java
index 7c27b424d4..8bc84649fc 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/AbstractDBTraceDataComponent.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/AbstractDBTraceDataComponent.java
@@ -25,6 +25,7 @@ import ghidra.program.model.data.DataType;
import ghidra.program.model.lang.Language;
import ghidra.trace.database.DBTrace;
import ghidra.trace.database.data.DBTraceDataSettingsAdapter.DBTraceDataSettingsSpace;
+import ghidra.trace.model.guest.TraceGuestPlatform;
import ghidra.trace.model.thread.TraceThread;
import ghidra.util.LockHold;
@@ -82,6 +83,11 @@ public abstract class AbstractDBTraceDataComponent implements DBTraceDefinedData
return root.getThread();
}
+ @Override
+ public TraceGuestPlatform getGuestPlatform() {
+ return root.getGuestPlatform();
+ }
+
@Override
public Language getLanguage() {
return root.getLanguage();
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCodeManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCodeManager.java
index 02395493d3..4789e9777d 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCodeManager.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCodeManager.java
@@ -25,10 +25,11 @@ import java.util.concurrent.locks.ReadWriteLock;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalNotification;
-import com.google.common.collect.*;
+import com.google.common.collect.Range;
import db.DBHandle;
import db.DBRecord;
+import ghidra.lifecycle.Internal;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.ContextChangeException;
@@ -41,7 +42,9 @@ import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter;
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.AddressDBFieldCodec;
import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.DecodesAddresses;
import ghidra.trace.database.data.DBTraceDataTypeManager;
-import ghidra.trace.database.language.DBTraceLanguageManager;
+import ghidra.trace.database.guest.DBTraceGuestPlatform;
+import ghidra.trace.database.guest.DBTracePlatformManager;
+import ghidra.trace.database.guest.DBTraceGuestPlatform.DBTraceGuestLanguage;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager;
import ghidra.trace.database.space.DBTraceDelegatingManager;
@@ -90,7 +93,7 @@ public class DBTraceCodeManager
static DBObjectColumn DELAY_COLUMN;
@DBAnnotatedField(column = LANGUAGE_COLUMN_NAME)
- private int langKey;
+ private int languageKey;
@DBAnnotatedField(column = BYTES_COLUMN_NAME)
private byte[] bytes;
@DBAnnotatedField(column = CONTEXT_COLUMN_NAME)
@@ -100,6 +103,8 @@ public class DBTraceCodeManager
@DBAnnotatedField(column = DELAY_COLUMN_NAME)
private boolean delaySlot;
+ private InstructionPrototype prototype;
+
private DBTraceCodeManager manager;
public DBTraceCodePrototypeEntry(DBTraceCodeManager manager, DBCachedObjectStore> store,
@@ -113,21 +118,33 @@ public class DBTraceCodeManager
return manager.overlayAdapter;
}
- void set(int langKey, byte[] bytes, byte[] context, Address address, boolean delaySlot) {
- this.langKey = langKey;
+ void set(DBTraceGuestLanguage languageEntry, byte[] bytes, byte[] context, Address address,
+ boolean delaySlot) {
+ this.languageKey = (int) (languageEntry == null ? -1 : languageEntry.getKey());
this.bytes = bytes;
this.context = context;
this.address = address;
this.delaySlot = delaySlot;
update(LANGUAGE_COLUMN, BYTES_COLUMN, CONTEXT_COLUMN, ADDRESS_COLUMN, DELAY_COLUMN);
+ this.prototype = parsePrototype();
}
- int getLanguageKey() {
- return langKey;
+ @Override
+ protected void fresh(boolean created) throws IOException {
+ super.fresh(created);
+ if (created) {
+ return;
+ }
+ this.prototype = parsePrototype();
}
- InstructionPrototype parsePrototype() {
- Language language = manager.languageManager.getLanguageByKey(langKey);
+ public InstructionPrototype getPrototype() {
+ return prototype;
+ }
+
+ private InstructionPrototype parsePrototype() {
+ DBTraceGuestLanguage guest = manager.platformManager.getLanguageByKey(languageKey);
+ Language language = guest == null ? manager.baseLanguage : guest.getLanguage();
MemBuffer memBuffer = new ByteMemBufferImpl(address, bytes, language.isBigEndian());
ProcessorContext ctx =
new ProtoProcessorContext(getBaseContextValue(language, context, address));
@@ -168,13 +185,14 @@ public class DBTraceCodeManager
return max;
}
- protected final DBTraceLanguageManager languageManager;
+ protected final DBTracePlatformManager platformManager;
protected final DBTraceDataTypeManager dataTypeManager;
protected final DBTraceOverlaySpaceAdapter overlayAdapter;
protected final DBTraceReferenceManager referenceManager;
protected final DBCachedObjectStore protoStore;
- protected final BiMap protoMap = HashBiMap.create();
+ protected final Map entriesByProto =
+ new HashMap<>();
protected final DBTraceCodeUnitsMemoryView codeUnits = new DBTraceCodeUnitsMemoryView(this);
protected final DBTraceInstructionsMemoryView instructions =
@@ -196,11 +214,11 @@ public class DBTraceCodeManager
public DBTraceCodeManager(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock,
TaskMonitor monitor, Language baseLanguage, DBTrace trace,
- DBTraceThreadManager threadManager, DBTraceLanguageManager languageManager,
+ DBTraceThreadManager threadManager, DBTracePlatformManager platformManager,
DBTraceDataTypeManager dataTypeManager, DBTraceOverlaySpaceAdapter overlayAdapter,
DBTraceReferenceManager referenceManager) throws IOException, VersionException {
super(NAME, dbh, openMode, lock, monitor, baseLanguage, trace, threadManager);
- this.languageManager = languageManager;
+ this.platformManager = platformManager;
this.dataTypeManager = dataTypeManager;
this.overlayAdapter = overlayAdapter;
this.referenceManager = referenceManager;
@@ -230,7 +248,7 @@ public class DBTraceCodeManager
// NOTE: Should already own write lock
for (DBTraceCodePrototypeEntry protoEnt : protoStore.asMap().values()) {
// NOTE: No need to check if it exists. This is only called on new or after clear
- protoMap.put(protoEnt.parsePrototype(), (int) protoEnt.getKey());
+ entriesByProto.put(protoEnt.prototype, protoEnt);
}
}
@@ -239,8 +257,8 @@ public class DBTraceCodeManager
return Arrays.copyOfRange(bytes, bytes.length / 2, bytes.length);
}
- protected int doRecordPrototype(InstructionPrototype prototype, MemBuffer memBuffer,
- ProcessorContextView context) {
+ protected DBTraceCodePrototypeEntry doRecordPrototype(InstructionPrototype prototype,
+ DBTraceGuestLanguage guest, MemBuffer memBuffer, ProcessorContextView context) {
DBTraceCodePrototypeEntry protoEnt = protoStore.create();
byte[] bytes = new byte[prototype.getLength()];
if (memBuffer.getBytes(bytes, 0) != bytes.length) {
@@ -255,20 +273,20 @@ public class DBTraceCodeManager
RegisterValue value = context.getRegisterValue(baseCtxReg);
ctx = value == null ? null : valueBytes(value);
}
- protoEnt.set(languageManager.getKeyForLanguage(prototype.getLanguage()), bytes, ctx,
- memBuffer.getAddress(), prototype.isInDelaySlot());
- return (int) protoEnt.getKey();
+ protoEnt.set(guest, bytes, ctx, memBuffer.getAddress(), prototype.isInDelaySlot());
+ return protoEnt;
}
- protected int findOrRecordPrototype(InstructionPrototype prototype, MemBuffer memBuffer,
- ProcessorContextView context) {
+ protected DBTraceCodePrototypeEntry findOrRecordPrototype(InstructionPrototype prototype,
+ DBTraceGuestLanguage guest, MemBuffer memBuffer, ProcessorContextView context) {
// NOTE: Must already have write lock
- return protoMap.computeIfAbsent(prototype,
- p -> doRecordPrototype(prototype, memBuffer, context));
+ return entriesByProto.computeIfAbsent(prototype,
+ p -> doRecordPrototype(prototype, guest, memBuffer, context));
}
protected InstructionPrototype getPrototypeByKey(int key) {
- return protoMap.inverse().get(key);
+ DBTraceCodePrototypeEntry protoEnt = protoStore.getObjectAt(key);
+ return protoEnt == null ? null : protoEnt.prototype;
}
@Override
@@ -326,35 +344,43 @@ public class DBTraceCodeManager
return getForRegisterSpace(frame, createIfAbsent);
}
- // Internal
+ @Internal
public void replaceDataTypes(long oldID, long newID) {
TODO();
}
- // Internal
+ @Internal
public void clearData(LinkedList deletedDataTypeIds, TaskMonitor monitor) {
TODO();
}
- // Internal
- public void clearLanguage(Range span, AddressRange range, int langKey,
+ @Internal
+ public void clearPlatform(Range span, AddressRange range, DBTraceGuestPlatform guest,
TaskMonitor monitor) throws CancelledException {
delegateDeleteV(range.getAddressSpace(),
- m -> m.clearLanguage(span, range, langKey, monitor));
+ m -> m.clearPlatform(span, range, guest, monitor));
}
- // Internal
- public void deleteLanguage(int langKey, TaskMonitor monitor) throws CancelledException {
+ @Internal
+ public void deletePlatform(DBTraceGuestPlatform guest, TaskMonitor monitor)
+ throws CancelledException {
// TODO: Use sub-monitors when available
for (DBTraceCodeSpace codeSpace : memSpaces.values()) {
- codeSpace.clearLanguage(Range.all(), codeSpace.all, langKey, monitor);
+ codeSpace.clearPlatform(Range.all(), codeSpace.all, guest, monitor);
}
for (DBTraceCodeRegisterSpace codeSpace : regSpaces.values()) {
// TODO: I don't know any way to get guest instructions into register space
// The mapping manager does (should) not allow guest register addresses
// TODO: Test this if I ever get guest data units
- codeSpace.clearLanguage(Range.all(), codeSpace.all, langKey, monitor);
+ // TODO: I think explicit per-thread/frame register spaces will be going away, anyway
+ // They'll just be path-named overlays on register space?
+ codeSpace.clearPlatform(Range.all(), codeSpace.all, guest, monitor);
}
+ }
+
+ @Internal
+ public void deleteLangauge(DBTraceGuestLanguage guest, TaskMonitor monitor)
+ throws CancelledException {
monitor.setMessage("Clearing instruction prototypes");
monitor.setMaximum(protoStore.getRecordCount());
for (Iterator it = protoStore.asMap().values().iterator(); it
@@ -362,11 +388,11 @@ public class DBTraceCodeManager
monitor.checkCanceled();
monitor.incrementProgress(1);
DBTraceCodePrototypeEntry protoEnt = it.next();
- if (langKey != protoEnt.langKey) {
+ if (protoEnt.prototype.getLanguage() != guest.getLanguage()) {
continue;
}
it.remove();
- protoMap.inverse().remove((int) protoEnt.getKey());
+ entriesByProto.remove(protoEnt.prototype);
}
}
@@ -374,7 +400,7 @@ public class DBTraceCodeManager
public void invalidateCache(boolean all) {
try (LockHold hold = LockHold.lock(lock.writeLock())) {
protoStore.invalidateCache();
- protoMap.clear();
+ entriesByProto.clear();
loadPrototypes();
super.invalidateCache(all);
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCodeSpace.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCodeSpace.java
index 0e4d7f91b8..5df815aeac 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCodeSpace.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCodeSpace.java
@@ -32,6 +32,7 @@ import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.trace.database.DBTrace;
import ghidra.trace.database.DBTraceUtils;
import ghidra.trace.database.data.DBTraceDataTypeManager;
+import ghidra.trace.database.guest.DBTraceGuestPlatform;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapSpace;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager.DBTraceSpaceEntry;
@@ -125,8 +126,8 @@ public class DBTraceCodeSpace implements TraceCodeSpace, DBTraceSpaceBased {
return new DBTraceCodeUnitsView(this);
}
- void clearLanguage(Range span, AddressRange range, int langKey, TaskMonitor monitor)
- throws CancelledException {
+ void clearPlatform(Range span, AddressRange range, DBTraceGuestPlatform guest,
+ TaskMonitor monitor) throws CancelledException {
// Note "makeWay" does not apply here.
// Units should be enclosed by guest mapping.
// TODO: Use sub-monitors when available
@@ -141,8 +142,7 @@ public class DBTraceCodeSpace implements TraceCodeSpace, DBTraceSpaceBased {
TraceAddressSnapRangeQuery.intersecting(range, span)).values()) {
monitor.checkCanceled();
monitor.incrementProgress(1);
- if (langKey != manager.protoStore.getObjectAt(
- instruction.getPrototypeKey()).getLanguageKey()) {
+ if (instruction.guest != guest) {
continue;
}
instructionMapSpace.deleteData(instruction);
@@ -154,7 +154,7 @@ public class DBTraceCodeSpace implements TraceCodeSpace, DBTraceSpaceBased {
TraceAddressSnapRangeQuery.intersecting(range, span)).values()) {
monitor.checkCanceled();
monitor.incrementProgress(1);
- if (langKey != dataUnit.getLanguageKey()) {
+ if (dataUnit.guest != guest) {
continue;
}
// TODO: I don't yet have guest-language data units.
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceData.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceData.java
index c16c32a13e..58373cb5bf 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceData.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceData.java
@@ -26,7 +26,9 @@ import ghidra.program.model.data.*;
import ghidra.program.model.lang.Language;
import ghidra.trace.database.DBTraceUtils;
import ghidra.trace.database.data.DBTraceDataSettingsAdapter.DBTraceDataSettingsSpace;
+import ghidra.trace.database.guest.DBTraceGuestPlatform;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree;
+import ghidra.trace.model.guest.TraceGuestPlatform;
import ghidra.util.LockHold;
import ghidra.util.database.DBCachedObjectStore;
import ghidra.util.database.DBObjectColumn;
@@ -37,11 +39,11 @@ public class DBTraceData extends AbstractDBTraceCodeUnit
implements DBTraceDefinedDataAdapter {
private static final String TABLE_NAME = "Data";
- static final String LANGUAGE_COLUMN_NAME = "Language";
+ static final String PLATFORM_COLUMN_NAME = "Platform";
static final String DATATYPE_COLUMN_NAME = "DataType";
- @DBAnnotatedColumn(LANGUAGE_COLUMN_NAME)
- static DBObjectColumn LANGUAGE_COLUMN;
+ @DBAnnotatedColumn(PLATFORM_COLUMN_NAME)
+ static DBObjectColumn PLATFORM_COLUMN;
@DBAnnotatedColumn(DATATYPE_COLUMN_NAME)
static DBObjectColumn DATATYPE_COLUMN;
@@ -49,12 +51,12 @@ public class DBTraceData extends AbstractDBTraceCodeUnit
return DBTraceUtils.tableName(TABLE_NAME, space, threadKey, frameLevel);
}
- @DBAnnotatedField(column = LANGUAGE_COLUMN_NAME)
- private int langKey;
+ @DBAnnotatedField(column = PLATFORM_COLUMN_NAME)
+ private int platformKey;
@DBAnnotatedField(column = DATATYPE_COLUMN_NAME)
private long dataTypeID;
- protected Language language;
+ protected DBTraceGuestPlatform guest;
protected DataType dataType;
protected DataType baseDataType;
protected Settings defaultSettings;
@@ -73,9 +75,9 @@ public class DBTraceData extends AbstractDBTraceCodeUnit
if (created) {
return;
}
- language = space.manager.languageManager.getLanguageByKey(langKey);
- if (language == null) {
- throw new IOException("Data table is corrupt. Missing language: " + langKey);
+ guest = space.manager.platformManager.getPlatformByKey(platformKey);
+ if (guest == null && platformKey != -1) {
+ throw new IOException("Data table is corrupt. Missing platform: " + platformKey);
}
dataType = space.dataTypeManager.getDataType(dataTypeID);
if (dataType == null) {
@@ -100,16 +102,17 @@ public class DBTraceData extends AbstractDBTraceCodeUnit
return this;
}
- protected void set(Language language, DataType dataType) {
- this.language = language;
- this.langKey = space.manager.languageManager.getKeyForLanguage(language);
+ protected void set(DBTraceGuestPlatform platform, DataType dataType) {
+ this.platformKey = (int) (platform == null ? -1 : platform.getKey());
this.dataTypeID = space.dataTypeManager.getResolvedID(dataType);
+ update(PLATFORM_COLUMN, DATATYPE_COLUMN);
+
+ this.guest = platform;
// Use the stored dataType, not the given one, in case it's different
this.dataType = space.dataTypeManager.getDataType(dataTypeID);
assert this.dataType != null;
- this.baseDataType = getBaseDataType(this.dataType);
this.defaultSettings = this.dataType.getDefaultSettings();
- update(LANGUAGE_COLUMN, DATATYPE_COLUMN);
+ this.baseDataType = getBaseDataType(this.dataType);
}
protected int getDataTypeLength() {
@@ -117,7 +120,7 @@ public class DBTraceData extends AbstractDBTraceCodeUnit
// TODO: Also need to know where this address maps into the other language's spaces....
// NOTE: Using default data space for now
// TODO: I may not need this Pointer check, as clone(dtm) should adjust already
- return language.getDefaultDataSpace().getPointerSize();
+ return getLanguage().getDefaultDataSpace().getPointerSize();
}
return dataType.getLength(); // -1 is checked elsewhere
}
@@ -129,6 +132,11 @@ public class DBTraceData extends AbstractDBTraceCodeUnit
return dt;
}
+ @Override
+ public TraceGuestPlatform getGuestPlatform() {
+ return guest;
+ }
+
@Override
public void delete() {
try (LockHold hold = LockHold.lock(space.lock.writeLock())) {
@@ -149,11 +157,7 @@ public class DBTraceData extends AbstractDBTraceCodeUnit
@Override
public Language getLanguage() {
- return language;
- }
-
- int getLanguageKey() {
- return langKey;
+ return guest == null ? space.baseLanguage : guest.getLanguage();
}
@Override
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceDefinedDataView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceDefinedDataView.java
index 102e1289f7..766e3884cb 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceDefinedDataView.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceDefinedDataView.java
@@ -145,7 +145,8 @@ public class DBTraceDefinedDataView extends AbstractBaseDBTraceDefinedUnitsView<
}
DBTraceData created = space.dataMapSpace.put(tasr, null);
- created.set(space.baseLanguage, dataType);
+ // TODO: data units with a guest platform
+ created.set(null, dataType);
// TODO: Explicitly remove undefined from cache, or let weak refs take care of it?
cacheForContaining.notifyNewEntry(lifespan, createdRange, created);
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceInstruction.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceInstruction.java
index 83f32ce23e..fa43e43bde 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceInstruction.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceInstruction.java
@@ -32,11 +32,13 @@ import ghidra.program.model.symbol.*;
import ghidra.trace.database.DBTraceUtils;
import ghidra.trace.database.context.DBTraceRegisterContextManager;
import ghidra.trace.database.context.DBTraceRegisterContextSpace;
-import ghidra.trace.database.language.DBTraceGuestLanguage;
+import ghidra.trace.database.guest.DBTraceGuestPlatform;
+import ghidra.trace.database.guest.DBTraceGuestPlatform.DBTraceGuestLanguage;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree;
import ghidra.trace.database.symbol.DBTraceReference;
import ghidra.trace.database.symbol.DBTraceReferenceSpace;
import ghidra.trace.model.Trace.TraceInstructionChangeType;
+import ghidra.trace.model.guest.TraceGuestPlatform;
import ghidra.trace.model.listing.TraceInstruction;
import ghidra.trace.model.symbol.TraceReference;
import ghidra.trace.util.*;
@@ -59,9 +61,12 @@ public class DBTraceInstruction extends AbstractDBTraceCodeUnit> FLOWOVERRIDE_SHIFT];
- doSetGuestMapping();
+ doSetGuestMapping(guest);
}
@Override
@@ -161,17 +186,6 @@ public class DBTraceInstruction extends AbstractDBTraceCodeUnit lifespan, Address address,
- InstructionPrototype prototype, ProcessorContextView context)
- throws CodeUnitInsertionException {
+ TraceGuestPlatform platform, InstructionPrototype prototype,
+ ProcessorContextView context) throws CodeUnitInsertionException {
return delegateWrite(address.getAddressSpace(),
- m -> m.create(lifespan, address, prototype, context));
+ m -> m.create(lifespan, address, platform, prototype, context));
}
@Override
- public AddressSetView addInstructionSet(Range lifespan, InstructionSet instructionSet,
- boolean overwrite) {
- InstructionSet mappedSet =
- manager.getTrace().getLanguageManager().mapGuestInstructionAddressesToHost(
- instructionSet);
+ public AddressSetView addInstructionSet(Range lifespan, TraceGuestPlatform platform,
+ InstructionSet instructionSet, boolean overwrite) {
+ InstructionSet mappedSet = manager.platformManager
+ .mapGuestInstructionAddressesToHost(platform, instructionSet);
Map breakDown = new HashMap<>();
// TODO: I'm not sure the consequences of breaking an instruction set down.
@@ -74,8 +74,8 @@ public class DBTraceInstructionsMemoryView
try (LockHold hold = LockHold.lock(manager.writeLock())) {
for (Entry entry : breakDown.entrySet()) {
DBTraceInstructionsView instructionsView = getForSpace(entry.getKey(), true);
- result.add(
- instructionsView.addInstructionSet(lifespan, entry.getValue(), overwrite));
+ result.add(instructionsView.addInstructionSet(lifespan, platform, entry.getValue(),
+ overwrite));
}
return result;
}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceInstructionsView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceInstructionsView.java
index a7d16110da..49e23d0797 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceInstructionsView.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceInstructionsView.java
@@ -29,9 +29,11 @@ import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.trace.database.DBTraceUtils;
import ghidra.trace.database.context.DBTraceRegisterContextManager;
import ghidra.trace.database.context.DBTraceRegisterContextSpace;
+import ghidra.trace.database.guest.DBTraceGuestPlatform;
import ghidra.trace.database.memory.DBTraceMemorySpace;
import ghidra.trace.model.ImmutableTraceAddressSnapRange;
import ghidra.trace.model.Trace.TraceCodeChangeType;
+import ghidra.trace.model.guest.TraceGuestPlatform;
import ghidra.trace.model.TraceAddressSnapRange;
import ghidra.trace.model.listing.TraceInstruction;
import ghidra.trace.model.listing.TraceInstructionsView;
@@ -50,6 +52,8 @@ public class DBTraceInstructionsView extends AbstractBaseDBTraceDefinedUnitsView
protected class InstructionBlockAdder {
private final Set skipDelaySlots;
+ private final Range lifespan;
+ private final DBTraceGuestPlatform platform;
private final InstructionBlock block;
private final Address errorAddress;
private final InstructionError conflict;
@@ -57,19 +61,22 @@ public class DBTraceInstructionsView extends AbstractBaseDBTraceDefinedUnitsView
protected int count = 0;
- private InstructionBlockAdder(Set skipDelaySlots, InstructionBlock block,
- Address errorAddress, InstructionError conflict, CodeUnit conflictCodeUnit) {
+ private InstructionBlockAdder(Set skipDelaySlots, Range lifespan,
+ DBTraceGuestPlatform platform, InstructionBlock block, Address errorAddress,
+ InstructionError conflict, CodeUnit conflictCodeUnit) {
this.skipDelaySlots = skipDelaySlots;
+ this.lifespan = lifespan;
+ this.platform = platform;
this.block = block;
this.errorAddress = errorAddress;
this.conflict = conflict;
this.conflictCodeUnit = conflictCodeUnit;
}
- protected Instruction doCreateInstruction(Range lifespan, Address address,
+ protected Instruction doCreateInstruction(Address address,
InstructionPrototype prototype, Instruction protoInstr) {
try {
- Instruction created = doCreate(lifespan, address, prototype, protoInstr);
+ Instruction created = doCreate(lifespan, address, platform, prototype, protoInstr);
// copy override settings to replacement instruction
if (protoInstr.isFallThroughOverridden()) {
created.setFallThrough(protoInstr.getFallThrough());
@@ -97,8 +104,7 @@ public class DBTraceInstructionsView extends AbstractBaseDBTraceDefinedUnitsView
* @param areDelaySlots
* @return
*/
- protected Instruction doAddInstructions(Range lifespan, Iterator it,
- boolean areDelaySlots) {
+ protected Instruction doAddInstructions(Iterator it, boolean areDelaySlots) {
Instruction lastInstruction = null;
while (it.hasNext()) {
Instruction protoInstr = it.next();
@@ -139,10 +145,10 @@ public class DBTraceInstructionsView extends AbstractBaseDBTraceDefinedUnitsView
delayed.push(it.next());
}
lastInstruction = replaceIfNotNull(lastInstruction,
- doAddInstructions(lifespan, delayed.iterator(), true));
+ doAddInstructions(delayed.iterator(), true));
}
lastInstruction =
- doCreateInstruction(lifespan, startAddress, prototype, protoInstr);
+ doCreateInstruction(startAddress, prototype, protoInstr);
}
if (errorAddress != null && conflictCodeUnit == null &&
errorAddress.compareTo(startAddress) <= 0) {
@@ -179,9 +185,22 @@ public class DBTraceInstructionsView extends AbstractBaseDBTraceDefinedUnitsView
ctxSpace.setValue(language, newValue, tasr.getLifespan(), tasr.getRange());
}
+ protected boolean languagesAgree(DBTraceGuestPlatform platform,
+ InstructionPrototype prototype) {
+ if (platform == null) {
+ return prototype.getLanguage() == space.baseLanguage;
+ }
+ return prototype.getLanguage() == platform.getLanguage();
+ }
+
protected DBTraceInstruction doCreate(Range lifespan, Address address,
- InstructionPrototype prototype, ProcessorContextView context)
+ DBTraceGuestPlatform platform, InstructionPrototype prototype,
+ ProcessorContextView context)
throws CodeUnitInsertionException, AddressOverflowException {
+ if (!languagesAgree(platform, prototype)) {
+ throw new IllegalArgumentException("Platform and prototype disagree in language");
+ }
+
Address endAddress = address.addNoWrap(prototype.getLength() - 1);
AddressRangeImpl createdRange = new AddressRangeImpl(address, endAddress);
@@ -213,7 +232,7 @@ public class DBTraceInstructionsView extends AbstractBaseDBTraceDefinedUnitsView
doSetContexts(tasr, prototype.getLanguage(), context);
DBTraceInstruction created = space.instructionMapSpace.put(tasr, null);
- created.set(prototype, context);
+ created.set(platform, prototype, context);
cacheForContaining.notifyNewEntry(lifespan, createdRange, created);
cacheForSequence.notifyNewEntry(lifespan, createdRange, created);
@@ -227,10 +246,13 @@ public class DBTraceInstructionsView extends AbstractBaseDBTraceDefinedUnitsView
@Override
public DBTraceInstruction create(Range lifespan, Address address,
- InstructionPrototype prototype, ProcessorContextView context)
+ TraceGuestPlatform platform, InstructionPrototype prototype,
+ ProcessorContextView context)
throws CodeUnitInsertionException {
+ DBTraceGuestPlatform dbPlatform = space.manager.platformManager.assertMine(platform);
try (LockHold hold = LockHold.lock(space.lock.writeLock())) {
- DBTraceInstruction created = doCreate(lifespan, address, prototype, context);
+ DBTraceInstruction created =
+ doCreate(lifespan, address, dbPlatform, prototype, context);
space.trace.setChanged(new TraceChangeRecord<>(TraceCodeChangeType.ADDED,
space, created, created));
return created;
@@ -254,23 +276,26 @@ public class DBTraceInstructionsView extends AbstractBaseDBTraceDefinedUnitsView
OverlappingObjectIterator.CODE_UNIT, existing, OverlappingObjectIterator.CODE_UNIT);
}
- protected InstructionBlockAdder startAddingBlock(long startSnap, Set skipDelaySlots,
- InstructionBlock block) {
+ protected InstructionBlockAdder startAddingBlock(Range lifespan,
+ Set skipDelaySlots, DBTraceGuestPlatform platform, InstructionBlock block) {
InstructionError conflict = block.getInstructionConflict();
if (conflict == null) {
- return new InstructionBlockAdder(skipDelaySlots, block, null, null, null);
+ return new InstructionBlockAdder(skipDelaySlots, lifespan, platform, block, null, null,
+ null);
}
Address errorAddress = conflict.getInstructionAddress();
if (errorAddress == null) {
return null; // The whole block is considered in error
}
if (!conflict.getInstructionErrorType().isConflict) {
- return new InstructionBlockAdder(skipDelaySlots, block, errorAddress, conflict, null);
+ return new InstructionBlockAdder(skipDelaySlots, lifespan, platform, block,
+ errorAddress, conflict, null);
}
+ long startSnap = DBTraceUtils.lowerEndpoint(lifespan);
CodeUnit conflictCodeUnit =
space.definedUnits.getAt(startSnap, conflict.getConflictAddress());
- return new InstructionBlockAdder(skipDelaySlots, block, errorAddress, conflict,
- conflictCodeUnit);
+ return new InstructionBlockAdder(skipDelaySlots, lifespan, platform, block, errorAddress,
+ conflict, conflictCodeUnit);
}
/**
@@ -359,8 +384,9 @@ public class DBTraceInstructionsView extends AbstractBaseDBTraceDefinedUnitsView
}
@Override
- public AddressSetView addInstructionSet(Range lifespan, InstructionSet instructionSet,
- boolean overwrite) {
+ public AddressSetView addInstructionSet(Range lifespan, TraceGuestPlatform platform,
+ InstructionSet instructionSet, boolean overwrite) {
+ DBTraceGuestPlatform dbPlatform = space.manager.platformManager.assertMine(platform);
// NOTE: Partly derived from CodeManager#addInstructions()
// Attempted to factor more fluently
AddressSet result = new AddressSet();
@@ -378,12 +404,12 @@ public class DBTraceInstructionsView extends AbstractBaseDBTraceDefinedUnitsView
// Add blocks
for (InstructionBlock block : instructionSet) {
- InstructionBlockAdder adder = startAddingBlock(startSnap, skipDelaySlots, block);
+ InstructionBlockAdder adder =
+ startAddingBlock(lifespan, skipDelaySlots, dbPlatform, block);
if (adder == null) {
continue;
}
- Instruction lastInstruction =
- adder.doAddInstructions(lifespan, block.iterator(), false);
+ Instruction lastInstruction = adder.doAddInstructions(block.iterator(), false);
block.setInstructionsAddedCount(adder.count);
if (lastInstruction != null) {
Address maxAddress = DBTraceCodeManager.instructionMax(lastInstruction, true);
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/UndefinedDBTraceData.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/UndefinedDBTraceData.java
index 74b9624585..ea21d51139 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/UndefinedDBTraceData.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/UndefinedDBTraceData.java
@@ -33,6 +33,7 @@ import ghidra.trace.database.memory.DBTraceMemorySpace;
import ghidra.trace.database.space.DBTraceSpaceKey;
import ghidra.trace.model.ImmutableTraceAddressSnapRange;
import ghidra.trace.model.TraceAddressSnapRange;
+import ghidra.trace.model.guest.TraceGuestPlatform;
import ghidra.trace.model.listing.TraceData;
import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.util.TraceAddressSpace;
@@ -80,6 +81,11 @@ public class UndefinedDBTraceData implements DBTraceDataAdapter, DBTraceSpaceKey
return trace.getBaseLanguage();
}
+ @Override
+ public TraceGuestPlatform getGuestPlatform() {
+ return null;
+ }
+
@Override
public AddressRange getRange() {
// TODO: Cache this?
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewListing.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewListing.java
index 15aa7d9b6d..90304a28d0 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewListing.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewListing.java
@@ -725,27 +725,25 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
public Instruction createInstruction(Address addr, InstructionPrototype prototype,
MemBuffer memBuf, ProcessorContextView context) throws CodeUnitInsertionException {
// TODO: Why memBuf? Can it vary from program memory?
- try (LockHold hold = program.trace.lockWrite()) {
- return codeOperations.instructions()
- .create(Range.atLeast(program.snap), addr,
- prototype, context);
- }
+ // TODO: Per-platform views?
+ return codeOperations.instructions()
+ .create(Range.atLeast(program.snap), addr, null, prototype, context);
}
@Override
public AddressSetView addInstructions(InstructionSet instructionSet, boolean overwrite)
throws CodeUnitInsertionException {
+ // TODO: Per-platform views?
return codeOperations.instructions()
- .addInstructionSet(Range.atLeast(program.snap),
- instructionSet, overwrite);
+ .addInstructionSet(Range.atLeast(program.snap), null, instructionSet,
+ overwrite);
}
@Override
public Data createData(Address addr, DataType dataType, int length)
throws CodeUnitInsertionException {
return codeOperations.definedData()
- .create(Range.atLeast(program.snap), addr, dataType,
- length);
+ .create(Range.atLeast(program.snap), addr, dataType, length);
}
@Override
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceObjectStack.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceObjectStack.java
index bf04fbdaa4..a4c981d0aa 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceObjectStack.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceObjectStack.java
@@ -181,10 +181,16 @@ public class DBTraceObjectStack implements TraceObjectStack, DBTraceObjectInterf
protected TraceStackFrame doGetFrame(int level) {
TargetObjectSchema schema = object.getTargetSchema();
PathPredicates matcher = schema.searchFor(TargetStackFrame.class, true);
- matcher = matcher.applyKeys(PathUtils.makeIndex(level));
- return object.getSuccessors(computeSpan(), matcher)
+ PathPredicates decMatcher = matcher.applyKeys(PathUtils.makeIndex(level));
+ PathPredicates hexMatcher = matcher.applyKeys("0x" + Integer.toHexString(level));
+ Range span = computeSpan();
+ return object.getSuccessors(span, decMatcher)
.findAny()
.map(p -> p.getDestination(object).queryInterface(TraceObjectStackFrame.class))
+ .or(() -> object.getSuccessors(span, hexMatcher)
+ .findAny()
+ .map(p -> p.getDestination(object)
+ .queryInterface(TraceObjectStackFrame.class)))
.orElse(null);
}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceObjectStackFrame.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceObjectStackFrame.java
index ed25c063f3..4b8fb64e50 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceObjectStackFrame.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceObjectStackFrame.java
@@ -65,7 +65,7 @@ public class DBTraceObjectStackFrame implements TraceObjectStackFrame, DBTraceOb
}
String index = PathUtils.parseIndex(k);
try {
- return Integer.parseInt(index, 10); // TODO: How to know the radix?
+ return Integer.decode(index);
// TODO: Perhaps just have an attribute that is its level?
}
catch (NumberFormatException e) {
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/DBTraceObject.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/DBTraceObject.java
index 19debaeaca..ffa3f42f13 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/DBTraceObject.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/DBTraceObject.java
@@ -353,6 +353,32 @@ public class DBTraceObject extends DBAnnotatedObject implements TraceObject {
}
}
+ protected void collectNonRangedAttributes(List super DBTraceObjectValue> result) {
+ for (DBTraceObjectValue val : manager.valuesByTriple
+ .sub(new PrimaryTriple(this, "", Long.MIN_VALUE), true,
+ new PrimaryTriple(this, "[", Long.MIN_VALUE), false)
+ .values()) {
+ result.add(val);
+ }
+ for (DBTraceObjectValue val : manager.valuesByTriple
+ .tail(new PrimaryTriple(this, "\\", Long.MIN_VALUE), true)
+ .values()) {
+ if (val.getParent() != this) {
+ break;
+ }
+ result.add(val);
+ }
+ }
+
+ protected void collectNonRangedElements(List super DBTraceObjectValue> result) {
+ for (DBTraceObjectValue val : manager.valuesByTriple
+ .sub(new PrimaryTriple(this, "[", Long.MIN_VALUE), true,
+ new PrimaryTriple(this, "\\", Long.MIN_VALUE), false)
+ .values()) {
+ result.add(val);
+ }
+ }
+
protected boolean doHasAnyNonRangedValues() {
for (DBTraceObjectValue val : manager.valuesByTriple
.tail(new PrimaryTriple(this, "", Long.MIN_VALUE), true)
@@ -377,6 +403,38 @@ public class DBTraceObject extends DBAnnotatedObject implements TraceObject {
}
}
+ protected void collectRangedAttributes(
+ Collection super DBTraceObjectAddressRangeValue> result) {
+ for (DBTraceAddressSnapRangePropertyMapSpace space //
+ : manager.rangeValueMap.getActiveMemorySpaces()) {
+ for (DBTraceObjectAddressRangeValue val : space.values()) {
+ if (val.getParent() != this) {
+ continue;
+ }
+ if (!PathUtils.isName(val.getEntryKey())) {
+ continue;
+ }
+ result.add(val);
+ }
+ }
+ }
+
+ protected void collectRangedElements(
+ Collection super DBTraceObjectAddressRangeValue> result) {
+ for (DBTraceAddressSnapRangePropertyMapSpace space //
+ : manager.rangeValueMap.getActiveMemorySpaces()) {
+ for (DBTraceObjectAddressRangeValue val : space.values()) {
+ if (val.getParent() != this) {
+ continue;
+ }
+ if (!PathUtils.isIndex(val.getEntryKey())) {
+ continue;
+ }
+ result.add(val);
+ }
+ }
+ }
+
protected boolean doHasAnyRangedValues() {
for (DBTraceAddressSnapRangePropertyMapSpace space //
: manager.rangeValueMap.getActiveMemorySpaces()) {
@@ -415,45 +473,29 @@ public class DBTraceObject extends DBAnnotatedObject implements TraceObject {
}
}
- protected Collection extends DBTraceObjectValue> doGetElements() {
- List result = new ArrayList<>();
- for (DBTraceObjectValue val : manager.valuesByTriple
- .sub(new PrimaryTriple(this, "[", Long.MIN_VALUE), true,
- new PrimaryTriple(this, "\\", Long.MIN_VALUE), false)
- .values()) {
- result.add(val);
- }
+ protected Collection extends InternalTraceObjectValue> doGetElements() {
+ List result = new ArrayList<>();
+ collectNonRangedElements(result);
+ collectRangedElements(result);
return result;
}
@Override
- public Collection extends DBTraceObjectValue> getElements() {
+ public Collection extends InternalTraceObjectValue> getElements() {
try (LockHold hold = manager.trace.lockRead()) {
return doGetElements();
}
}
- protected Collection extends DBTraceObjectValue> doGetAttributes() {
- List result = new ArrayList<>();
- for (DBTraceObjectValue val : manager.valuesByTriple
- .sub(new PrimaryTriple(this, "", Long.MIN_VALUE), true,
- new PrimaryTriple(this, "[", Long.MIN_VALUE), false)
- .values()) {
- result.add(val);
- }
- for (DBTraceObjectValue val : manager.valuesByTriple
- .tail(new PrimaryTriple(this, "\\", Long.MIN_VALUE), true)
- .values()) {
- if (val.getParent() != this) {
- break;
- }
- result.add(val);
- }
+ protected Collection extends InternalTraceObjectValue> doGetAttributes() {
+ List result = new ArrayList<>();
+ collectNonRangedAttributes(result);
+ collectRangedAttributes(result);
return result;
}
@Override
- public Collection extends DBTraceObjectValue> getAttributes() {
+ public Collection extends InternalTraceObjectValue> getAttributes() {
try (LockHold hold = manager.trace.lockRead()) {
return doGetAttributes();
}
@@ -525,7 +567,7 @@ public class DBTraceObject extends DBAnnotatedObject implements TraceObject {
return floor;
}
- protected Stream doGetNonRangedValues(Range span, String key,
+ protected Stream doGetOrderedNonRangedValues(Range span, String key,
boolean forward) {
DBCachedObjectIndex sub = manager.valuesByTriple.sub(
new PrimaryTriple(this, key, DBTraceUtils.lowerEndpoint(span)), true,
@@ -552,7 +594,7 @@ public class DBTraceObject extends DBAnnotatedObject implements TraceObject {
return null;
}
- protected Stream doGetRangedValues(Range span,
+ protected Stream doGetOrderedRangedValues(Range span,
String key, boolean forward) {
Rectangle2DDirection dir = forward
? Rectangle2DDirection.BOTTOMMOST
@@ -590,8 +632,8 @@ public class DBTraceObject extends DBAnnotatedObject implements TraceObject {
protected Stream doGetOrderedValues(Range span, String key,
boolean forward) {
- Stream nrVals = doGetNonRangedValues(span, key, forward);
- Stream rVals = doGetRangedValues(span, key, forward);
+ Stream nrVals = doGetOrderedNonRangedValues(span, key, forward);
+ Stream rVals = doGetOrderedRangedValues(span, key, forward);
Comparator order = forward ? Comparator.naturalOrder() : Comparator.reverseOrder();
Comparator comparator =
Comparator.comparing(v -> v.getMinSnap(), order);
@@ -883,9 +925,14 @@ public class DBTraceObject extends DBAnnotatedObject implements TraceObject {
manager.trace.setChanged(rec);
for (TraceObjectInterface iface : ifaces.values()) {
DBTraceObjectInterface dbIface = (DBTraceObjectInterface) iface;
- TraceChangeRecord, ?> evt = dbIface.translateEvent(rec);
- if (evt != null) {
- manager.trace.setChanged(evt);
+ try {
+ TraceChangeRecord, ?> evt = dbIface.translateEvent(rec);
+ if (evt != null) {
+ manager.trace.setChanged(evt);
+ }
+ }
+ catch (Throwable t) {
+ Msg.error(this, "Error while translating event " + rec + " for interface " + iface);
}
}
}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/InternalOrderedSuccessorsVisitor.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/InternalOrderedSuccessorsVisitor.java
index 6012fedf2d..9deced413c 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/InternalOrderedSuccessorsVisitor.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/InternalOrderedSuccessorsVisitor.java
@@ -50,7 +50,7 @@ public class InternalOrderedSuccessorsVisitor implements SpanIntersectingVisitor
// Singleton path, so if I match, no successor can
return VisitResult.INCLUDE_FINISH;
}
- if (value.getChildOrNull() == null || predicates.successorCouldMatch(keyList, true)) {
+ if (value.getChildOrNull() == null || !predicates.successorCouldMatch(keyList, true)) {
return VisitResult.EXCLUDE_FINISH;
}
return VisitResult.EXCLUDE_CONTINUE;
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/InternalSuccessorsRelativeVisitor.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/InternalSuccessorsRelativeVisitor.java
index ec13c70842..0f40c644d3 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/InternalSuccessorsRelativeVisitor.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/InternalSuccessorsRelativeVisitor.java
@@ -60,7 +60,7 @@ public class InternalSuccessorsRelativeVisitor implements SpanIntersectingVisito
return Stream.empty();
}
- Stream extends DBTraceObjectValue> attrStream;
+ Stream extends InternalTraceObjectValue> attrStream;
if (nextKeys.contains("")) {
attrStream = object.doGetAttributes()
.stream()
@@ -70,7 +70,7 @@ public class InternalSuccessorsRelativeVisitor implements SpanIntersectingVisito
attrStream = Stream.empty();
}
- Stream extends DBTraceObjectValue> elemStream;
+ Stream extends InternalTraceObjectValue> elemStream;
if (nextKeys.contains("[]")) {
elemStream = object.doGetElements()
.stream()
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/Trace.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/Trace.java
index 3a9d798ee4..f44bebf149 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/Trace.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/Trace.java
@@ -32,7 +32,7 @@ import ghidra.trace.model.breakpoint.TraceBreakpoint;
import ghidra.trace.model.breakpoint.TraceBreakpointManager;
import ghidra.trace.model.context.TraceRegisterContextManager;
import ghidra.trace.model.data.TraceBasedDataTypeManager;
-import ghidra.trace.model.language.TraceLanguageManager;
+import ghidra.trace.model.guest.TracePlatformManager;
import ghidra.trace.model.listing.*;
import ghidra.trace.model.memory.*;
import ghidra.trace.model.modules.*;
@@ -399,7 +399,7 @@ public interface Trace extends DataTypeManagerDomainObject {
TraceEquateManager getEquateManager();
- TraceLanguageManager getLanguageManager();
+ TracePlatformManager getPlatformManager();
TraceMemoryManager getMemoryManager();
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/guest/TraceGuestPlatform.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/guest/TraceGuestPlatform.java
new file mode 100644
index 0000000000..2bbd5f783d
--- /dev/null
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/guest/TraceGuestPlatform.java
@@ -0,0 +1,132 @@
+/* ###
+ * 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.model.guest;
+
+import ghidra.program.model.address.*;
+import ghidra.program.model.lang.*;
+import ghidra.program.model.mem.MemBuffer;
+import ghidra.trace.model.Trace;
+import ghidra.util.exception.CancelledException;
+import ghidra.util.task.TaskMonitor;
+
+public interface TraceGuestPlatform {
+ /**
+ * Get the trace
+ *
+ * @return the trace
+ */
+ Trace getTrace();
+
+ /**
+ * Get the language of the guest platform
+ *
+ * @return the language
+ */
+ Language getLanguage();
+
+ /**
+ * Get the address factory of the guest platform
+ *
+ * @return the factory
+ */
+ default AddressFactory getAddressFactory() {
+ return getLanguage().getAddressFactory();
+ }
+
+ /**
+ * Get the compiler of the guest platform
+ *
+ * @return the compiler spec
+ */
+ CompilerSpec getCompilerSpec();
+
+ /**
+ * Add an adress mapping from host to guest
+ *
+ * @param hostStart the starting host address (mapped to guestStart)
+ * @param guestStart the starting guest address (mapped to hostStart)
+ * @param length the length of the range to map
+ * @return the mapped range
+ * @throws AddressOverflowException if length is too long for either start
+ */
+ TraceGuestPlatformMappedRange addMappedRange(Address hostStart, Address guestStart, long length)
+ throws AddressOverflowException;
+
+ /**
+ * Get the addresses in the host which are mapped to somewhere in the guest
+ *
+ * @return the address set
+ */
+ AddressSetView getHostAddressSet();
+
+ /**
+ * Get the addresses in the guest which are mapped to somehere in the host
+ *
+ * @return the address set
+ */
+ AddressSetView getGuestAddressSet();
+
+ /**
+ * Map an address from host to guest
+ *
+ * @param hostAddress the host address
+ * @return the guest address
+ */
+ Address mapHostToGuest(Address hostAddress);
+
+ /**
+ * Map an address from guest to host
+ *
+ * @param guestAddress the guest address
+ * @return the host address
+ */
+ Address mapGuestToHost(Address guestAddress);
+
+ /**
+ * Get a memory buffer, which presents the host bytes in the guest address space
+ *
+ *
+ * This, with pseudo-disassembly, is the primary mechanism for adding instructions in the guest
+ * language.
+ *
+ * @param snap the snap, up to which the most recent memory changes are presented
+ * @param guestAddress the starting address in the guest space
+ * @return the mapped memory buffer
+ */
+ MemBuffer getMappedMemBuffer(long snap, Address guestAddress);
+
+ /**
+ * Copy the given instruction set, but with addresses mapped from the guest space to the host
+ * space
+ *
+ *
+ * Instructions which do not map are silently ignored. If concerned, the caller ought to examine
+ * the resulting instruction set and/or the resulting address set after it is added to the
+ * trace. A single instruction cannot span two mapped ranges, even if the comprised bytes are
+ * consecutive in the guest space. Mapping such an instruction back into the host space would
+ * cause the instruction to be split in the middle, which is not possible. Thus, such
+ * instructions are silently ignored.
+ *
+ * @param set the instruction set in the guest space
+ * @return the instruction set in the host space
+ */
+ InstructionSet mapGuestInstructionAddressesToHost(InstructionSet set);
+
+ /**
+ * Remove the mapped language, including all code units of the language
+ */
+ void delete(TaskMonitor monitor) throws CancelledException;
+}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/language/TraceGuestLanguageMappedRange.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/guest/TraceGuestPlatformMappedRange.java
similarity index 83%
rename from Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/language/TraceGuestLanguageMappedRange.java
rename to Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/guest/TraceGuestPlatformMappedRange.java
index 666eb38589..b382999be6 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/language/TraceGuestLanguageMappedRange.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/guest/TraceGuestPlatformMappedRange.java
@@ -13,20 +13,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.trace.model.language;
+package ghidra.trace.model.guest;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressRange;
+import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.lang.Language;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
-public interface TraceGuestLanguageMappedRange {
+public interface TraceGuestPlatformMappedRange {
Language getHostLanguage();
+ CompilerSpec getHostCompilerSpec();
+
AddressRange getHostRange();
- Language getGuestLanguage();
+ TraceGuestPlatform getGuestPlatform();
AddressRange getGuestRange();
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/guest/TracePlatformManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/guest/TracePlatformManager.java
new file mode 100644
index 0000000000..3807f622b5
--- /dev/null
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/guest/TracePlatformManager.java
@@ -0,0 +1,74 @@
+/* ###
+ * 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.model.guest;
+
+import java.util.Collection;
+
+import ghidra.program.model.lang.CompilerSpec;
+import ghidra.program.model.lang.Language;
+
+/**
+ * Allows the addition of "guest platforms" for disassembling in multiple languages.
+ *
+ *
+ * TODO: Allow the placement of data units with alternative data organization.
+ */
+public interface TracePlatformManager {
+ /**
+ * Get the base language of the trace
+ *
+ * @return the language
+ */
+ Language getBaseLanguage();
+
+ /**
+ * Get the base compiler spec of the trace
+ *
+ * @return the compiler spec
+ */
+ CompilerSpec getBaseCompilerSpec();
+
+ /**
+ * Add a guest platform
+ *
+ * @param compilerSpec the compiler spec, which cannot be the base compiler spec
+ * @return the new platform
+ */
+ TraceGuestPlatform addGuestPlatform(CompilerSpec compilerSpec);
+
+ /**
+ * Get the guest platform for the given compiler spec
+ *
+ * @param compilerSpec the compiler spec. For the base compiler spec, this will return null.
+ * @return the platform, if found, or null
+ */
+ TraceGuestPlatform getGuestPlatform(CompilerSpec compilerSpec);
+
+ /**
+ * Get or add a platform for the given compiler spec
+ *
+ * @param compilerSpec the compiler spec
+ * @return the new or existing platform, or null if compiler spec is the base compiler spec
+ */
+ TraceGuestPlatform getOrAddGuestPlatform(CompilerSpec compilerSpec);
+
+ /**
+ * Get all guest platforms
+ *
+ * @return the collection of platforms
+ */
+ Collection getGuestPlatforms();
+}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/language/TraceGuestLanguage.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/language/TraceGuestLanguage.java
deleted file mode 100644
index 24227e3795..0000000000
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/language/TraceGuestLanguage.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/* ###
- * 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.model.language;
-
-import ghidra.program.model.address.*;
-import ghidra.program.model.lang.InstructionSet;
-import ghidra.program.model.lang.Language;
-import ghidra.program.model.mem.MemBuffer;
-import ghidra.util.exception.CancelledException;
-import ghidra.util.task.TaskMonitor;
-
-public interface TraceGuestLanguage {
- Language getLanguage();
-
- TraceGuestLanguageMappedRange addMappedRange(Address hostStart, Address guestStart, long length)
- throws AddressOverflowException;
-
- AddressSetView getHostAddressSet();
-
- AddressSetView getGuestAddressSet();
-
- Address mapHostToGuest(Address hostAddress);
-
- Address mapGuestToHost(Address guestAddress);
-
- /**
- * Get a memory buffer which presents the host bytes in the guest address space
- *
- * This, with pseudo-disassembly, is the primary mechanism for adding instructions in the guest
- * language.
- *
- * @param snap the snap, up to which the most recent memory changes are presented
- * @param guestAddress the starting address in the guest space
- * @return the mapped memory buffer
- */
- MemBuffer getMappedMemBuffer(long snap, Address guestAddress);
-
- /**
- * Copy the given instruction set, but with addresses mapped from the guest space to the host
- * space
- *
- * Instructions which do not mapped are silently ignored. If concerned, the caller ought to
- * examine the resulting instruction set and/or the resulting address set after it is added to
- * the trace. A single instruction cannot span two mapped ranges, even if the comprised bytes
- * are consecutive in the guest space. Mapping such an instruction back into the host space
- * would cause the instruction to be split in the middle, which is not possible. Thus, such
- * instructions are silently ignored.
- *
- * @param set the instruction set in the guest space
- * @return the instruction set in the host space
- */
- InstructionSet mapGuestInstructionAddressesToHost(InstructionSet set);
-
- /**
- * Remove the mapped language, including all code units of the language
- */
- void delete(TaskMonitor monitor) throws CancelledException;
-}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/listing/TraceCodeUnit.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/listing/TraceCodeUnit.java
index 33e3cdd693..d01b9d3290 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/listing/TraceCodeUnit.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/listing/TraceCodeUnit.java
@@ -25,6 +25,7 @@ import ghidra.program.model.listing.CodeUnit;
import ghidra.program.model.util.TypeMismatchException;
import ghidra.trace.model.Trace;
import ghidra.trace.model.TraceAddressSnapRange;
+import ghidra.trace.model.guest.TraceGuestPlatform;
import ghidra.trace.model.program.TraceProgramView;
import ghidra.trace.model.symbol.TraceReference;
import ghidra.trace.model.thread.TraceThread;
@@ -42,6 +43,13 @@ public interface TraceCodeUnit extends CodeUnit {
*/
Trace getTrace();
+ /**
+ * If the unit is for a guest platform, get it
+ *
+ * @return the guest platform, or null if it's for the host platform
+ */
+ TraceGuestPlatform getGuestPlatform();
+
@Override
TraceProgramView getProgram();
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/listing/TraceInstructionsView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/listing/TraceInstructionsView.java
index 6932d1ad7a..adb00b7bbd 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/listing/TraceInstructionsView.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/listing/TraceInstructionsView.java
@@ -21,21 +21,37 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.lang.*;
import ghidra.program.model.util.CodeUnitInsertionException;
+import ghidra.trace.model.guest.TraceGuestPlatform;
public interface TraceInstructionsView extends TraceBaseDefinedUnitsView {
- TraceInstruction create(Range lifespan, Address address, InstructionPrototype prototype,
- ProcessorContextView context) throws CodeUnitInsertionException;
+ /**
+ * Create an instruction
+ *
+ * @param lifespan the lifespan for the instruction unit
+ * @param address the starting address of the instruction
+ * @param platform the optional guest platform, null for the host
+ * @param prototype the instruction prototype
+ * @param context the input disassembly context for the instruction
+ * @return the new instruction
+ * @throws CodeUnitInsertionException if the instruction cannot be created
+ */
+ TraceInstruction create(Range lifespan, Address address, TraceGuestPlatform platform,
+ InstructionPrototype prototype, ProcessorContextView context)
+ throws CodeUnitInsertionException;
/**
- * TODO
+ * Create several instructions
*
- * NOTE: Does not throw {@link CodeUnitInsertionException}. Conflicts are instead recorded in
- * the {@code instructionSet}
+ *
+ * NOTE: This does not throw {@link CodeUnitInsertionException}. Conflicts are instead
+ * recorded in the {@code instructionSet}.
*
+ * @param lifespan the lifespan for all instruction units
+ * @param platform the optional guest platform, null for the host
* @param instructionSet the set of instructions to add
- * @param overwrite {@code true} to replace conflicting instructions
- * @return the address set of instructions actually added
+ * @param overwrite true to replace conflicting instructions
+ * @return the (host) address set of instructions actually added
*/
- AddressSetView addInstructionSet(Range lifespan, InstructionSet instructionSet,
- boolean overwrite);
+ AddressSetView addInstructionSet(Range lifespan, TraceGuestPlatform platform,
+ InstructionSet instructionSet, boolean overwrite);
}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/util/DefaultTraceTimeViewport.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/util/DefaultTraceTimeViewport.java
index 4dec7b42e3..d59c0baa52 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/util/DefaultTraceTimeViewport.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/util/DefaultTraceTimeViewport.java
@@ -106,7 +106,7 @@ public class DefaultTraceTimeViewport implements TraceTimeViewport {
* may need the DB's lock, esp., considering user callbacks, then it must first acquire
* the DB lock.
*/
- protected final List> ordered = new ArrayList<>(List.of(Range.singleton(0L)));
+ protected final List> ordered = new ArrayList<>();
protected final RangeSet spanSet = TreeRangeSet.create();
protected final ForSnapshotsListener listener = new ForSnapshotsListener();
protected final ListenerSet changeListeners = new ListenerSet<>(Runnable.class);
@@ -114,6 +114,10 @@ public class DefaultTraceTimeViewport implements TraceTimeViewport {
protected long snap = 0;
public DefaultTraceTimeViewport(Trace trace) {
+ Range zero = Range.singleton(0L);
+ spanSet.add(zero);
+ ordered.add(zero);
+
this.trace = trace;
trace.addCloseListener(listener);
trace.addListener(listener);
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java
index 3f9aa4c654..8c5c042843 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java
@@ -26,7 +26,8 @@ import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.util.*;
+import java.util.Collection;
+import java.util.List;
import com.google.common.collect.Range;
@@ -45,13 +46,12 @@ import ghidra.program.model.symbol.SourceType;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.program.util.DefaultLanguageService;
import ghidra.trace.database.bookmark.*;
-import ghidra.trace.database.language.DBTraceGuestLanguage;
import ghidra.trace.database.listing.*;
import ghidra.trace.database.memory.DBTraceMemoryManager;
import ghidra.trace.database.symbol.DBTraceReference;
import ghidra.trace.database.thread.DBTraceThreadManager;
import ghidra.trace.model.*;
-import ghidra.trace.model.language.TraceGuestLanguage;
+import ghidra.trace.model.guest.TraceGuestPlatform;
import ghidra.trace.model.thread.TraceThread;
import ghidra.util.Msg;
import ghidra.util.database.DBOpenMode;
@@ -102,7 +102,7 @@ public class ToyDBTraceBuilder implements AutoCloseable {
return addr(language, offset);
}
- public Address addr(TraceGuestLanguage lang, long offset) {
+ public Address addr(TraceGuestPlatform lang, long offset) {
return lang.getLanguage().getDefaultSpace().getAddress(offset);
}
@@ -114,7 +114,7 @@ public class ToyDBTraceBuilder implements AutoCloseable {
return data(language, offset);
}
- public Address data(TraceGuestLanguage lang, long offset) {
+ public Address data(TraceGuestPlatform lang, long offset) {
return data(lang.getLanguage(), offset);
}
@@ -150,11 +150,11 @@ public class ToyDBTraceBuilder implements AutoCloseable {
return drng(language, start, end);
}
- public AddressRange range(TraceGuestLanguage lang, long start, long end) {
+ public AddressRange range(TraceGuestPlatform lang, long start, long end) {
return range(lang.getLanguage(), start, end);
}
- public AddressRange drng(TraceGuestLanguage lang, long start, long end) {
+ public AddressRange drng(TraceGuestPlatform lang, long start, long end) {
return drng(lang.getLanguage(), start, end);
}
@@ -246,9 +246,10 @@ public class ToyDBTraceBuilder implements AutoCloseable {
}
public DBTraceInstruction addInstruction(long snap, Address start,
- @SuppressWarnings("hiding") Language language) throws CodeUnitInsertionException {
+ TraceGuestPlatform guest) throws CodeUnitInsertionException {
DBTraceMemoryManager memory = trace.getMemoryManager();
DBTraceCodeManager code = trace.getCodeManager();
+ Language language = guest == null ? this.language : guest.getLanguage();
Disassembler dis = Disassembler.getDisassembler(language, language.getAddressFactory(),
new ConsoleTaskMonitor(), msg -> Msg.info(this, "Listener: " + msg));
RegisterValue defaultContextValue = trace.getRegisterContextManager()
@@ -256,27 +257,25 @@ public class ToyDBTraceBuilder implements AutoCloseable {
.getDefaultDisassemblyContext();
MemBuffer memBuf;
- if (language == null || Objects.equals(this.language, language)) {
+ if (guest == null) {
memBuf = memory.getBufferAt(snap, start);
}
else {
- DBTraceGuestLanguage guest = trace.getLanguageManager().getGuestLanguage(language);
memBuf = guest.getMappedMemBuffer(snap, guest.mapHostToGuest(start));
}
InstructionBlock block = dis.pseudoDisassembleBlock(memBuf, defaultContextValue, 1);
Instruction pseudoIns = block.iterator().next();
return code.instructions()
- .create(Range.atLeast(snap), start, pseudoIns.getPrototype(),
- pseudoIns);
+ .create(Range.atLeast(snap), start, guest, pseudoIns.getPrototype(), pseudoIns);
}
public DBTraceInstruction addInstruction(long snap, Address start,
- @SuppressWarnings("hiding") Language language, ByteBuffer buf)
+ TraceGuestPlatform guest, ByteBuffer buf)
throws CodeUnitInsertionException {
int length = buf.remaining();
DBTraceMemoryManager memory = trace.getMemoryManager();
memory.putBytes(snap, start, buf);
- DBTraceInstruction instruction = addInstruction(snap, start, language);
+ DBTraceInstruction instruction = addInstruction(snap, start, guest);
assertEquals(length, instruction.getLength());
return instruction;
}
@@ -345,4 +344,9 @@ public class ToyDBTraceBuilder implements AutoCloseable {
public Language getLanguage(String id) throws LanguageNotFoundException {
return languageService.getLanguage(new LanguageID(id));
}
+
+ public CompilerSpec getCompiler(String langID, String compID)
+ throws CompilerSpecNotFoundException, LanguageNotFoundException {
+ return getLanguage(langID).getCompilerSpecByID(new CompilerSpecID(compID));
+ }
}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/language/DBTraceLanguageManagerTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/guest/DBTracePlatformManagerTest.java
similarity index 58%
rename from Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/language/DBTraceLanguageManagerTest.java
rename to Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/guest/DBTracePlatformManagerTest.java
index 38858d115d..77e44db80d 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/language/DBTraceLanguageManagerTest.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/guest/DBTracePlatformManagerTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.trace.database.language;
+package ghidra.trace.database.guest;
import static org.junit.Assert.*;
@@ -23,24 +23,21 @@ import java.util.*;
import org.junit.*;
-import ghidra.program.model.address.AddressOverflowException;
-import ghidra.program.model.lang.LanguageNotFoundException;
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
import ghidra.trace.database.ToyDBTraceBuilder;
-import ghidra.trace.model.language.TraceGuestLanguage;
+import ghidra.trace.database.guest.*;
+import ghidra.trace.model.guest.TraceGuestPlatform;
import ghidra.util.database.UndoableTransaction;
-import ghidra.util.exception.CancelledException;
-import ghidra.util.exception.VersionException;
import ghidra.util.task.ConsoleTaskMonitor;
-public class DBTraceLanguageManagerTest extends AbstractGhidraHeadlessIntegrationTest {
+public class DBTracePlatformManagerTest extends AbstractGhidraHeadlessIntegrationTest {
protected ToyDBTraceBuilder b;
- protected DBTraceLanguageManager manager;
+ protected DBTracePlatformManager manager;
@Before
public void setUpLanguageManagerTest() throws IOException {
b = new ToyDBTraceBuilder("Testing", "Toy:BE:64:default");
- manager = b.trace.getLanguageManager();
+ manager = b.trace.getPlatformManager();
}
@After
@@ -55,82 +52,108 @@ public class DBTraceLanguageManagerTest extends AbstractGhidraHeadlessIntegratio
}
@Test
- public void testAddGuestLanguage() throws LanguageNotFoundException {
+ public void testGetBaseCompilerSpec() {
+ assertEquals("default", manager.getBaseCompilerSpec().getCompilerSpecID().getIdAsString());
+ }
+
+ @Test
+ public void testAddGuestPlatform() throws Throwable {
try (UndoableTransaction tid = b.startTransaction()) {
assertEquals(0, manager.languageStore.getRecordCount());
- manager.addGuestLanguage(b.getLanguage("x86:LE:32:default"));
+ assertEquals(0, manager.platformStore.getRecordCount());
+ manager.addGuestPlatform(b.getCompiler("x86:LE:32:default", "gcc"));
assertEquals(1, manager.languageStore.getRecordCount());
-
- try { // Cannot add base language as guest
- manager.addGuestLanguage(b.getLanguage("Toy:BE:64:default"));
- fail();
- }
- catch (IllegalArgumentException e) {
- // pass
- }
+ assertEquals(1, manager.platformStore.getRecordCount());
}
}
@Test
- public void testGetGuestLanguages() throws LanguageNotFoundException {
- DBTraceGuestLanguage guest;
+ public void testAddGuestPlatformHostCompilerErr() throws Throwable {
try (UndoableTransaction tid = b.startTransaction()) {
- assertTrue(manager.getGuestLanguages().isEmpty());
- guest = manager.addGuestLanguage(b.getLanguage("x86:LE:32:default"));
+ manager.addGuestPlatform(b.getLanguage("Toy:BE:64:default").getDefaultCompilerSpec());
+ fail();
+ }
+ catch (IllegalArgumentException e) {
+ // pass, pending consistency check
}
- assertEquals(Set.of(guest), new HashSet<>(manager.getGuestLanguages()));
+ assertEquals(0, manager.languageStore.getRecordCount());
+ assertEquals(0, manager.platformStore.getRecordCount());
+ assertTrue(manager.getGuestPlatforms().isEmpty());
}
@Test
- public void testAddLanguageThenUndo() throws IOException {
+ public void testAddGuestPlatformHostLanguage() throws Throwable {
try (UndoableTransaction tid = b.startTransaction()) {
- manager.addGuestLanguage(b.getLanguage("x86:LE:32:default"));
+ assertEquals(0, manager.languageStore.getRecordCount());
+ assertEquals(0, manager.platformStore.getRecordCount());
+ manager.addGuestPlatform(b.getCompiler("Toy:BE:64:default", "long8"));
+ assertEquals(0, manager.languageStore.getRecordCount());
+ assertEquals(1, manager.platformStore.getRecordCount());
+ }
+ }
+
+ @Test
+ public void testGetGuestPlatforms() throws Throwable {
+ DBTraceGuestPlatform guest;
+ try (UndoableTransaction tid = b.startTransaction()) {
+ assertTrue(manager.getGuestPlatforms().isEmpty());
+ guest = manager.addGuestPlatform(b.getCompiler("x86:LE:32:default", "gcc"));
+ }
+
+ assertEquals(Set.of(guest), new HashSet<>(manager.getGuestPlatforms()));
+ }
+
+ @Test
+ public void testAddPlatformThenUndo() throws Throwable {
+ try (UndoableTransaction tid = b.startTransaction()) {
+ manager.addGuestPlatform(b.getCompiler("x86:LE:32:default", "gcc"));
}
b.trace.undo();
- assertTrue(manager.getGuestLanguages().isEmpty());
+ assertTrue(manager.getGuestPlatforms().isEmpty());
}
@Test
- public void testAddLanguageThenSaveAndLoad()
- throws CancelledException, IOException, VersionException {
+ public void testAddPlatformThenSaveAndLoad() throws Throwable {
try (UndoableTransaction tid = b.startTransaction()) {
- manager.addGuestLanguage(b.getLanguage("x86:LE:32:default"));
+ manager.addGuestPlatform(b.getCompiler("x86:LE:32:default", "gcc"));
}
File saved = b.save();
try (ToyDBTraceBuilder r = new ToyDBTraceBuilder(saved)) {
- Collection guestLanguages =
- r.trace.getLanguageManager().getGuestLanguages();
- assertEquals(1, guestLanguages.size());
+ Collection guestPlatforms =
+ r.trace.getPlatformManager().getGuestPlatforms();
+ assertEquals(1, guestPlatforms.size());
+ TraceGuestPlatform platform = guestPlatforms.iterator().next();
assertEquals("x86:LE:32:default",
- guestLanguages.iterator().next().getLanguage().getLanguageID().getIdAsString());
+ platform.getLanguage().getLanguageID().getIdAsString());
+ assertEquals("gcc", platform.getCompilerSpec().getCompilerSpecID().getIdAsString());
}
}
@Test
- public void testDeleteGuestLanguage() throws LanguageNotFoundException, CancelledException {
- DBTraceGuestLanguage guest;
+ public void testDeleteGuestPlatform() throws Throwable {
+ DBTraceGuestPlatform guest;
try (UndoableTransaction tid = b.startTransaction()) {
- guest = manager.addGuestLanguage(b.getLanguage("x86:LE:32:default"));
+ guest = manager.addGuestPlatform(b.getCompiler("x86:LE:32:default", "gcc"));
}
try (UndoableTransaction tid = b.startTransaction()) {
guest.delete(new ConsoleTaskMonitor());
}
- assertEquals(0, manager.languageStore.getRecordCount());
- assertTrue(manager.entriesByLanguage.isEmpty());
+ assertEquals(0, manager.platformStore.getRecordCount());
+ assertTrue(manager.platformsByCompiler.isEmpty());
}
@Test
- public void testAddMappedRange() throws LanguageNotFoundException, AddressOverflowException {
+ public void testAddMappedRange() throws Throwable {
try (UndoableTransaction tid = b.startTransaction()) {
- DBTraceGuestLanguage guest =
- manager.addGuestLanguage(b.getLanguage("x86:LE:32:default"));
+ DBTraceGuestPlatform guest =
+ manager.addGuestPlatform(b.getCompiler("x86:LE:32:default", "gcc"));
assertEquals(0, manager.rangeMappingStore.getRecordCount());
guest.addMappedRange(b.addr(0x01000000), b.addr(guest, 0x02000000), 0x1000);
@@ -155,11 +178,10 @@ public class DBTraceLanguageManagerTest extends AbstractGhidraHeadlessIntegratio
}
@Test
- public void testGetHostAndGuestAddressSet()
- throws LanguageNotFoundException, AddressOverflowException {
+ public void testGetHostAndGuestAddressSet() throws Throwable {
try (UndoableTransaction tid = b.startTransaction()) {
- DBTraceGuestLanguage guest =
- manager.addGuestLanguage(b.getLanguage("x86:LE:32:default"));
+ DBTraceGuestPlatform guest =
+ manager.addGuestPlatform(b.getCompiler("x86:LE:32:default", "gcc"));
assertEquals(b.set(), guest.getHostAddressSet());
guest.addMappedRange(b.addr(0x01000000), b.addr(guest, 0x02000000), 0x1000);
@@ -169,10 +191,10 @@ public class DBTraceLanguageManagerTest extends AbstractGhidraHeadlessIntegratio
}
@Test
- public void testMapHostToGuest() throws LanguageNotFoundException, AddressOverflowException {
+ public void testMapHostToGuest() throws Throwable {
try (UndoableTransaction tid = b.startTransaction()) {
- DBTraceGuestLanguage guest =
- manager.addGuestLanguage(b.getLanguage("x86:LE:32:default"));
+ DBTraceGuestPlatform guest =
+ manager.addGuestPlatform(b.getCompiler("x86:LE:32:default", "gcc"));
guest.addMappedRange(b.addr(0x01000000), b.addr(guest, 0x02000000), 0x1000);
assertNull(guest.mapHostToGuest(b.addr(0x00000000)));
@@ -185,10 +207,10 @@ public class DBTraceLanguageManagerTest extends AbstractGhidraHeadlessIntegratio
}
@Test
- public void testMapGuestToHost() throws LanguageNotFoundException, AddressOverflowException {
+ public void testMapGuestToHost() throws Throwable {
try (UndoableTransaction tid = b.startTransaction()) {
- DBTraceGuestLanguage guest =
- manager.addGuestLanguage(b.getLanguage("x86:LE:32:default"));
+ DBTraceGuestPlatform guest =
+ manager.addGuestPlatform(b.getCompiler("x86:LE:32:default", "gcc"));
guest.addMappedRange(b.addr(0x01000000), b.addr(guest, 0x02000000), 0x1000);
assertNull(guest.mapGuestToHost(b.addr(0x00000000)));
@@ -201,30 +223,28 @@ public class DBTraceLanguageManagerTest extends AbstractGhidraHeadlessIntegratio
}
@Test
- public void testAddMappedRangeThenSaveAndLoad()
- throws AddressOverflowException, CancelledException, IOException, VersionException {
+ public void testAddMappedRangeThenSaveAndLoad() throws Throwable {
try (UndoableTransaction tid = b.startTransaction()) {
- DBTraceGuestLanguage guest =
- manager.addGuestLanguage(b.getLanguage("x86:LE:32:default"));
+ DBTraceGuestPlatform guest =
+ manager.addGuestPlatform(b.getCompiler("x86:LE:32:default", "gcc"));
guest.addMappedRange(b.addr(0x01000000), b.addr(guest, 0x02000000), 0x1000);
}
File saved = b.save();
try (ToyDBTraceBuilder r = new ToyDBTraceBuilder(saved)) {
- TraceGuestLanguage guest =
- r.trace.getLanguageManager().getGuestLanguages().iterator().next();
+ TraceGuestPlatform guest =
+ r.trace.getPlatformManager().getGuestPlatforms().iterator().next();
assertEquals(b.addr(guest, 0x02000800), guest.mapHostToGuest(b.addr(0x01000800)));
}
}
@Test
- public void testMappedRangeGetHostLanguage()
- throws LanguageNotFoundException, AddressOverflowException {
+ public void testMappedRangeGetHostLanguage() throws Throwable {
try (UndoableTransaction tid = b.startTransaction()) {
- DBTraceGuestLanguage guest =
- manager.addGuestLanguage(b.getLanguage("x86:LE:32:default"));
- DBTraceGuestLanguageMappedRange range =
+ DBTraceGuestPlatform guest =
+ manager.addGuestPlatform(b.getCompiler("x86:LE:32:default", "gcc"));
+ DBTraceGuestPlatformMappedRange range =
guest.addMappedRange(b.addr(0x01000000), b.addr(guest, 0x02000000), 0x1000);
assertEquals("Toy:BE:64:default",
range.getHostLanguage().getLanguageID().getIdAsString());
@@ -232,49 +252,44 @@ public class DBTraceLanguageManagerTest extends AbstractGhidraHeadlessIntegratio
}
@Test
- public void testMappedRangeGetHostRange()
- throws LanguageNotFoundException, AddressOverflowException {
+ public void testMappedRangeGetHostRange() throws Throwable {
try (UndoableTransaction tid = b.startTransaction()) {
- DBTraceGuestLanguage guest =
- manager.addGuestLanguage(b.getLanguage("x86:LE:32:default"));
- DBTraceGuestLanguageMappedRange range =
+ DBTraceGuestPlatform guest =
+ manager.addGuestPlatform(b.getCompiler("x86:LE:32:default", "gcc"));
+ DBTraceGuestPlatformMappedRange range =
guest.addMappedRange(b.addr(0x01000000), b.addr(guest, 0x02000000), 0x1000);
assertEquals(b.range(0x01000000, 0x01000fff), range.getHostRange());
}
}
@Test
- public void testMappedRangeGetGuestLanguage()
- throws LanguageNotFoundException, AddressOverflowException {
+ public void testMappedRangeGetGuestPlatform() throws Throwable {
try (UndoableTransaction tid = b.startTransaction()) {
- DBTraceGuestLanguage guest =
- manager.addGuestLanguage(b.getLanguage("x86:LE:32:default"));
- DBTraceGuestLanguageMappedRange range =
+ DBTraceGuestPlatform guest =
+ manager.addGuestPlatform(b.getCompiler("x86:LE:32:default", "gcc"));
+ DBTraceGuestPlatformMappedRange range =
guest.addMappedRange(b.addr(0x01000000), b.addr(guest, 0x02000000), 0x1000);
- assertEquals("x86:LE:32:default",
- range.getGuestLanguage().getLanguageID().getIdAsString());
+ assertEquals(guest, range.getGuestPlatform());
}
}
@Test
- public void testMappedRangeGetGuestRange()
- throws LanguageNotFoundException, AddressOverflowException {
+ public void testMappedRangeGetGuestRange() throws Throwable {
try (UndoableTransaction tid = b.startTransaction()) {
- DBTraceGuestLanguage guest =
- manager.addGuestLanguage(b.getLanguage("x86:LE:32:default"));
- DBTraceGuestLanguageMappedRange range =
+ DBTraceGuestPlatform guest =
+ manager.addGuestPlatform(b.getCompiler("x86:LE:32:default", "gcc"));
+ DBTraceGuestPlatformMappedRange range =
guest.addMappedRange(b.addr(0x01000000), b.addr(guest, 0x02000000), 0x1000);
assertEquals(b.range(guest, 0x02000000, 0x02000fff), range.getGuestRange());
}
}
@Test
- public void testDeleteMappedRange()
- throws LanguageNotFoundException, AddressOverflowException, CancelledException {
+ public void testDeleteMappedRange() throws Throwable {
try (UndoableTransaction tid = b.startTransaction()) {
- DBTraceGuestLanguage guest =
- manager.addGuestLanguage(b.getLanguage("x86:LE:32:default"));
- DBTraceGuestLanguageMappedRange range =
+ DBTraceGuestPlatform guest =
+ manager.addGuestPlatform(b.getCompiler("x86:LE:32:default", "gcc"));
+ DBTraceGuestPlatformMappedRange range =
guest.addMappedRange(b.addr(0x01000000), b.addr(guest, 0x02000000), 0x1000);
assertNotNull(guest.mapHostToGuest(b.addr(0x01000800))); // Sanity check
assertNotNull(guest.mapGuestToHost(b.addr(guest, 0x02000800))); // Sanity check
@@ -291,12 +306,11 @@ public class DBTraceLanguageManagerTest extends AbstractGhidraHeadlessIntegratio
}
@Test
- public void testDeleteMappedRangeThenUndo()
- throws AddressOverflowException, IOException, CancelledException {
- DBTraceGuestLanguage guest;
- DBTraceGuestLanguageMappedRange range;
+ public void testDeleteMappedRangeThenUndo() throws Throwable {
+ DBTraceGuestPlatform guest;
+ DBTraceGuestPlatformMappedRange range;
try (UndoableTransaction tid = b.startTransaction()) {
- guest = manager.addGuestLanguage(b.getLanguage("x86:LE:32:default"));
+ guest = manager.addGuestPlatform(b.getCompiler("x86:LE:32:default", "gcc"));
range = guest.addMappedRange(b.addr(0x01000000), b.addr(guest, 0x02000000), 0x1000);
assertNotNull(guest.mapHostToGuest(b.addr(0x01000800))); // Sanity check
assertNotNull(guest.mapGuestToHost(b.addr(guest, 0x02000800))); // Sanity check
@@ -310,19 +324,17 @@ public class DBTraceLanguageManagerTest extends AbstractGhidraHeadlessIntegratio
b.trace.undo();
- guest = manager.getGuestLanguage(b.getLanguage("x86:LE:32:default"));
-
+ guest = manager.getGuestPlatform(b.getCompiler("x86:LE:32:default", "gcc"));
assertNotNull(guest.mapHostToGuest(b.addr(0x01000800)));
assertNotNull(guest.mapGuestToHost(b.addr(guest, 0x02000800)));
}
@Test
- public void testDeleteGuestLanguageDeletesMappedRanges()
- throws LanguageNotFoundException, AddressOverflowException, CancelledException {
+ public void testDeleteGuestPlatformDeletesMappedRanges() throws Throwable {
// TODO: Check that it also deletes code units
- DBTraceGuestLanguage guest;
+ DBTraceGuestPlatform guest;
try (UndoableTransaction tid = b.startTransaction()) {
- guest = manager.addGuestLanguage(b.getLanguage("x86:LE:32:default"));
+ guest = manager.addGuestPlatform(b.getCompiler("x86:LE:32:default", "gcc"));
guest.addMappedRange(b.addr(0x01000000), b.addr(guest, 0x02000000), 0x1000);
}
@@ -333,12 +345,11 @@ public class DBTraceLanguageManagerTest extends AbstractGhidraHeadlessIntegratio
}
@Test
- public void testDeleteGuestLanguageThenUndo()
- throws AddressOverflowException, CancelledException, IOException {
+ public void testDeleteGuestPlatformThenUndo() throws Throwable {
// TODO: Check that it also deletes code units
- DBTraceGuestLanguage guest;
+ DBTraceGuestPlatform guest;
try (UndoableTransaction tid = b.startTransaction()) {
- guest = manager.addGuestLanguage(b.getLanguage("x86:LE:32:default"));
+ guest = manager.addGuestPlatform(b.getCompiler("x86:LE:32:default", "gcc"));
guest.addMappedRange(b.addr(0x01000000), b.addr(guest, 0x02000000), 0x1000);
}
@@ -348,7 +359,7 @@ public class DBTraceLanguageManagerTest extends AbstractGhidraHeadlessIntegratio
b.trace.undo();
- guest = manager.getGuestLanguage(b.getLanguage("x86:LE:32:default"));
+ guest = manager.getGuestPlatform(b.getCompiler("x86:LE:32:default", "gcc"));
assertEquals(b.addr(guest, 0x02000800), guest.mapHostToGuest(b.addr(0x01000800)));
}
}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/listing/DBTraceCodeManagerTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/listing/DBTraceCodeManagerTest.java
index 52c0525161..2d4c1b19d7 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/listing/DBTraceCodeManagerTest.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/listing/DBTraceCodeManagerTest.java
@@ -40,7 +40,7 @@ import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.database.context.DBTraceRegisterContextManager;
-import ghidra.trace.database.language.*;
+import ghidra.trace.database.guest.*;
import ghidra.trace.model.ImmutableTraceAddressSnapRange;
import ghidra.trace.model.listing.*;
import ghidra.trace.model.stack.TraceStack;
@@ -187,7 +187,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
@Test
public void testAddInstruction() throws CodeUnitInsertionException {
try (UndoableTransaction tid = b.startTransaction()) {
- b.addInstruction(0, b.addr(0x4004), b.language, b.buf(0xf4, 0));
+ b.addInstruction(0, b.addr(0x4004), null, b.buf(0xf4, 0));
}
}
@@ -196,7 +196,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
try (UndoableTransaction tid = b.startTransaction()) {
b.trace.getMemoryManager().putBytes(10, b.addr(0x4001), b.buf(0xaa));
TraceInstruction i4000 =
- b.addInstruction(0, b.addr(0x4000), b.language, b.buf(0xf4, 0));
+ b.addInstruction(0, b.addr(0x4000), null, b.buf(0xf4, 0));
assertEquals(Range.closed(0L, 9L), i4000.getLifespan());
}
}
@@ -206,15 +206,15 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
try (UndoableTransaction tid = b.startTransaction()) {
b.trace.getMemoryManager().putBytes(-5L, b.addr(0x4001), b.buf(0xaa));
TraceInstruction i4000 =
- b.addInstruction(-10, b.addr(0x4000), b.language, b.buf(0xf4, 0));
+ b.addInstruction(-10, b.addr(0x4000), null, b.buf(0xf4, 0));
assertEquals(Range.closed(-10L, -6L), i4000.getLifespan());
TraceInstruction i4004 =
- b.addInstruction(-1, b.addr(0x4004), b.language, b.buf(0xf4, 0));
+ b.addInstruction(-1, b.addr(0x4004), null, b.buf(0xf4, 0));
assertEquals(Range.closed(-1L, -1L), i4004.getLifespan());
TraceInstruction i4008 =
- b.addInstruction(-10, b.addr(0x4008), b.language, b.buf(0xf4, 0));
+ b.addInstruction(-10, b.addr(0x4008), null, b.buf(0xf4, 0));
assertEquals(Range.closed(-10L, -1L), i4008.getLifespan());
}
}
@@ -223,7 +223,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
public void testPutBytesTruncatesInstruction() throws CodeUnitInsertionException {
try (UndoableTransaction tid = b.startTransaction()) {
TraceInstruction i4000 =
- b.addInstruction(0, b.addr(0x4000), b.language, b.buf(0xf4, 0));
+ b.addInstruction(0, b.addr(0x4000), null, b.buf(0xf4, 0));
assertEquals(b.addr(0x4001), i4000.getMaxAddress());
assertEquals(Range.atLeast(0L), i4000.getLifespan());
b.trace.getMemoryManager().putBytes(10, b.addr(0x4001), b.buf(1));
@@ -236,7 +236,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
public void testPutBytesDeletesInstruction() throws CodeUnitInsertionException {
try (UndoableTransaction tid = b.startTransaction()) {
TraceInstruction i4000 =
- b.addInstruction(0, b.addr(0x4000), b.language, b.buf(0xf4, 0));
+ b.addInstruction(0, b.addr(0x4000), null, b.buf(0xf4, 0));
assertEquals(b.addr(0x4001), i4000.getMaxAddress());
assertEquals(Range.atLeast(0L), i4000.getLifespan());
b.trace.getMemoryManager().putBytes(0, b.addr(0x4001), b.buf(1));
@@ -267,14 +267,14 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
}
try {
- b.addInstruction(1, b.addr(0x4001), b.language);
+ b.addInstruction(1, b.addr(0x4001), null);
fail();
}
catch (CodeUnitInsertionException e) {
// pass
}
- b.addInstruction(0, b.addr(0x4004), b.language, b.buf(0xf4, 0));
+ b.addInstruction(0, b.addr(0x4004), null, b.buf(0xf4, 0));
try {
b.addData(1, b.addr(0x4005), ByteDataType.dataType, 1);
@@ -285,7 +285,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
}
try {
- b.addInstruction(1, b.addr(0x4005), b.language);
+ b.addInstruction(1, b.addr(0x4005), null);
}
catch (CodeUnitInsertionException e) {
// pass
@@ -350,8 +350,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
assertAllNullFunc(v -> v.getAt(9, b.addr(0x4003)));
assertUndefinedFunc(v -> v.getAt(9, b.addr(0x4004)));
- TraceInstruction i4005 =
- b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
+ TraceInstruction i4005 = b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
i4005.setEndSnap(5);
assertUndefinedFunc(v -> v.getAt(0, b.addr(0x4004)));
assertInstructionFunc(i4005, v -> v.getAt(0, b.addr(0x4005)));
@@ -384,8 +383,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
assertDataFunc(d4000, v -> v.getContaining(9, b.addr(0x4003)));
assertUndefinedFunc(v -> v.getContaining(9, b.addr(0x4004)));
- TraceInstruction i4005 =
- b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
+ TraceInstruction i4005 = b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
i4005.setEndSnap(5);
assertUndefinedFunc(v -> v.getContaining(0, b.addr(0x4004)));
@@ -451,7 +449,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
d4000.setEndSnap(9);
d4004 = b.addData(0, b.addr(0x4004), IntegerDataType.dataType, b.buf(5, 6, 7, 8));
d4004.setEndSnap(5);
- i4008 = b.addInstruction(0, b.addr(0x4008), b.language, b.buf(0xf4, 0));
+ i4008 = b.addInstruction(0, b.addr(0x4008), null, b.buf(0xf4, 0));
i4008.setEndSnap(9);
}
@@ -593,7 +591,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
d4000.setEndSnap(9);
d4004 = b.addData(0, b.addr(0x4004), IntegerDataType.dataType, b.buf(5, 6, 7, 8));
d4004.setEndSnap(5);
- i4008 = b.addInstruction(0, b.addr(0x4008), b.language, b.buf(0xf4, 0));
+ i4008 = b.addInstruction(0, b.addr(0x4008), null, b.buf(0xf4, 0));
i4008.setEndSnap(9);
}
@@ -732,7 +730,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
d4000.setEndSnap(9);
d4004 = b.addData(0, b.addr(0x4004), IntegerDataType.dataType, b.buf(5, 6, 7, 8));
d4004.setEndSnap(5);
- i4008 = b.addInstruction(0, b.addr(0x4008), b.language, b.buf(0xf4, 0));
+ i4008 = b.addInstruction(0, b.addr(0x4008), null, b.buf(0xf4, 0));
i4008.setEndSnap(9);
}
@@ -872,7 +870,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
d4000.setEndSnap(9);
d4004 = b.addData(0, b.addr(0x4004), IntegerDataType.dataType, b.buf(5, 6, 7, 8));
d4004.setEndSnap(5);
- i4008 = b.addInstruction(0, b.addr(0x4008), b.language, b.buf(0xf4, 0));
+ i4008 = b.addInstruction(0, b.addr(0x4008), null, b.buf(0xf4, 0));
i4008.setEndSnap(9);
}
@@ -1086,7 +1084,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
d4000.setEndSnap(9);
d4004 = b.addData(0, b.addr(0x4004), IntegerDataType.dataType, b.buf(5, 6, 7, 8));
d4004.setEndSnap(5);
- i4008 = b.addInstruction(0, b.addr(0x4008), b.language, b.buf(0xf4, 0));
+ i4008 = b.addInstruction(0, b.addr(0x4008), null, b.buf(0xf4, 0));
i4008.setEndSnap(9);
}
TraceData u3fff = manager.undefinedData().getAt(0, b.addr(0x3fff));
@@ -1139,7 +1137,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
TraceInstruction iCodeMax;
try (UndoableTransaction tid = b.startTransaction()) {
- iCodeMax = b.addInstruction(0, b.addr(-0x0002), b.language, b.buf(0xf4, 0));
+ iCodeMax = b.addInstruction(0, b.addr(-0x0002), null, b.buf(0xf4, 0));
}
assertEquals(iCodeMax, manager.codeUnits().getBefore(0, b.data(0x0000)));
@@ -1172,7 +1170,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
manager.undefinedData().getFloor(0, b.data(0x0003)));
try (UndoableTransaction tid = b.startTransaction()) {
- iCodeMax = b.addInstruction(0, b.addr(-0x0002), b.language, b.buf(0xf4, 0));
+ iCodeMax = b.addInstruction(0, b.addr(-0x0002), null, b.buf(0xf4, 0));
}
TraceData uCodePre = manager.undefinedData().getAt(0, b.addr(-0x0003));
assertUndefinedWithAddr(b.addr(-0x0003), uCodePre);
@@ -1211,7 +1209,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
try (UndoableTransaction tid = b.startTransaction()) {
d4000 = b.addData(0, b.addr(0x4000), IntegerDataType.dataType, b.buf(1, 2, 3, 4));
d4000.setEndSnap(9);
- i4008 = b.addInstruction(0, b.addr(0x4008), b.language, b.buf(0xf4, 0));
+ i4008 = b.addInstruction(0, b.addr(0x4008), null, b.buf(0xf4, 0));
i4008.setEndSnap(9);
}
@@ -1346,7 +1344,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
d4000.setEndSnap(9);
d4004 = b.addData(0, b.addr(0x4004), IntegerDataType.dataType, b.buf(5, 6, 7, 8));
d4004.setEndSnap(5);
- i4008 = b.addInstruction(0, b.addr(0x4008), b.language, b.buf(0xf4, 0));
+ i4008 = b.addInstruction(0, b.addr(0x4008), null, b.buf(0xf4, 0));
i4008.setEndSnap(9);
}
@@ -1416,7 +1414,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
d4000.setEndSnap(9);
d4004 = b.addData(0, b.addr(0x4004), IntegerDataType.dataType, b.buf(5, 6, 7, 8));
d4004.setEndSnap(5);
- i4008 = b.addInstruction(0, b.addr(0x4008), b.language, b.buf(0xf4, 0));
+ i4008 = b.addInstruction(0, b.addr(0x4008), null, b.buf(0xf4, 0));
i4008.setEndSnap(9);
}
@@ -1491,7 +1489,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
d4000.setEndSnap(9);
d4004 = b.addData(0, b.addr(0x4004), IntegerDataType.dataType, b.buf(5, 6, 7, 8));
d4004.setEndSnap(5);
- i4008 = b.addInstruction(0, b.addr(0x4008), b.language, b.buf(0xf4, 0));
+ i4008 = b.addInstruction(0, b.addr(0x4008), null, b.buf(0xf4, 0));
i4008.setEndSnap(9);
}
@@ -1575,7 +1573,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
d4000.setEndSnap(9);
d4004 = b.addData(0, b.addr(0x4004), IntegerDataType.dataType, b.buf(5, 6, 7, 8));
d4004.setEndSnap(5);
- i4008 = b.addInstruction(0, b.addr(0x4008), b.language, b.buf(0xf4, 0));
+ i4008 = b.addInstruction(0, b.addr(0x4008), null, b.buf(0xf4, 0));
i4008.setEndSnap(9);
}
@@ -1674,7 +1672,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
d4000.setEndSnap(9);
d4004 = b.addData(0, b.addr(0x4004), IntegerDataType.dataType, b.buf(5, 6, 7, 8));
d4004.setEndSnap(5);
- i4008 = b.addInstruction(0, b.addr(0x4008), b.language, b.buf(0xf4, 0));
+ i4008 = b.addInstruction(0, b.addr(0x4008), null, b.buf(0xf4, 0));
i4008.setEndSnap(9);
// Clear one of the data before a context space is created
@@ -1708,22 +1706,21 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
}
@Test
- @Ignore("Looks related to GP-479")
public void testAddGuestInstructionThenRemoveAndDelete() throws AddressOverflowException,
CodeUnitInsertionException, IOException, CancelledException {
- DBTraceLanguageManager langMan = b.trace.getLanguageManager();
+ DBTracePlatformManager langMan = b.trace.getPlatformManager();
Language x86 = getSLEIGH_X86_LANGUAGE();
- DBTraceGuestLanguage guest;
- DBTraceGuestLanguageMappedRange mappedRange;
+ DBTraceGuestPlatform guest;
+ DBTraceGuestPlatformMappedRange mappedRange;
TraceInstruction g4000;
TraceInstruction i4001;
TraceData d4003;
try (UndoableTransaction tid = b.startTransaction()) {
- guest = langMan.addGuestLanguage(x86);
+ guest = langMan.addGuestPlatform(x86.getDefaultCompilerSpec());
mappedRange = guest.addMappedRange(b.addr(0x0000), b.addr(guest, 0x0000), 1L << 32);
- g4000 = b.addInstruction(0, b.addr(0x4000), x86, b.buf(0x90));
- i4001 = b.addInstruction(0, b.addr(0x4001), b.language, b.buf(0xf4, 0));
+ g4000 = b.addInstruction(0, b.addr(0x4000), guest, b.buf(0x90));
+ i4001 = b.addInstruction(0, b.addr(0x4001), null, b.buf(0xf4, 0));
d4003 = b.addData(0, b.addr(0x4003), LongDataType.dataType, b.buf(1, 2, 3, 4));
}
@@ -1737,19 +1734,26 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
b.trace.undo();
- assertEquals(g4000, manager.codeUnits().getAt(0, b.addr(0x4000)));
+ // NB. The range deletion also deletes the guest unit, so it'll have a new identity
+ // TODO: Related to GP-479?
+ g4000 = manager.instructions().getAt(0, b.addr(0x4000));
+ assertNotNull(g4000);
+ assertEquals(guest, g4000.getGuestPlatform());
try (UndoableTransaction tid = b.startTransaction()) {
guest.delete(new ConsoleTaskMonitor());
}
assertUndefinedWithAddr(b.addr(0x4000), manager.codeUnits().getAt(0, b.addr(0x4000)));
- assertEquals(i4001, manager.codeUnits().getAt(0, b.addr(0x4001)));
- assertEquals(d4003, manager.codeUnits().getAt(0, b.addr(0x4003)));
+ // TODO: Definitely part of GP-479. These should be able to keep their identities.
+ //assertEquals(i4001, manager.codeUnits().getAt(0, b.addr(0x4001)));
+ //assertEquals(d4003, manager.codeUnits().getAt(0, b.addr(0x4003)));
+ assertNotNull(manager.instructions().getAt(0, b.addr(0x4001)));
+ assertNotNull(manager.definedData().getAt(0, b.addr(0x4003)));
}
@Test
public void testSaveAndLoad() throws Exception {
try (UndoableTransaction tid = b.startTransaction()) {
- b.addInstruction(0, b.addr(0x4004), b.language, b.buf(0xf4, 0));
+ b.addInstruction(0, b.addr(0x4004), null, b.buf(0xf4, 0));
TraceThread thread = b.getOrAddThread("Thread 1", 0);
DBTraceCodeRegisterSpace regCode = manager.getCodeRegisterSpace(thread, true);
@@ -1797,7 +1801,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
@Test
public void testUndoThenRedo() throws Exception {
try (UndoableTransaction tid = b.startTransaction()) {
- b.addInstruction(0, b.addr(0x4004), b.language, b.buf(0xf4, 0));
+ b.addInstruction(0, b.addr(0x4004), null, b.buf(0xf4, 0));
TraceThread thread = b.getOrAddThread("Thread 1", 0);
DBTraceCodeRegisterSpace regCode = manager.getCodeRegisterSpace(thread, true);
@@ -1850,7 +1854,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
b.trace.getBaseAddressFactory().getDefaultAddressSpace());
DBTraceCodeSpace space = manager.getCodeSpace(os, true);
- b.addInstruction(0, os.getAddress(0x4004), b.language, b.buf(0xf4, 0));
+ b.addInstruction(0, os.getAddress(0x4004), null, b.buf(0xf4, 0));
List all = new ArrayList<>();
space.definedUnits().get(0, true).forEach(all::add);
@@ -1859,9 +1863,5 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
}
}
- // TODO: Test using a context-sensitive language
- // TODO: Test using delay-slotted instructions (DBTraceCodemanager#instructionMax)
// TODO: How are lifespans of delay-slotted instructions bound to thatof the jump?
- // TODO: In language manager, test deleting a language clears instructions
- // TODO: In language manager, test unmapping a language clears instructions
}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/listing/DBTraceCodeUnitTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/listing/DBTraceCodeUnitTest.java
index a2f342e9fb..98873903f4 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/listing/DBTraceCodeUnitTest.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/listing/DBTraceCodeUnitTest.java
@@ -50,7 +50,7 @@ import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAdd
import ghidra.trace.database.memory.DBTraceMemoryRegisterSpace;
import ghidra.trace.database.memory.DBTraceMemorySpace;
import ghidra.trace.database.symbol.DBTraceReference;
-import ghidra.trace.model.language.TraceGuestLanguage;
+import ghidra.trace.model.guest.TraceGuestPlatform;
import ghidra.trace.model.listing.TraceData;
import ghidra.trace.model.listing.TraceInstruction;
import ghidra.trace.model.memory.TraceMemoryFlag;
@@ -242,7 +242,7 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
TraceOverlappedRegionException, DuplicateNameException {
TraceInstruction ins;
try (UndoableTransaction tid = b.startTransaction()) {
- ins = b.addInstruction(0, b.addr(0x4004), b.language, b.buf(0xf4, 0));
+ ins = b.addInstruction(0, b.addr(0x4004), null, b.buf(0xf4, 0));
}
TraceData und = manager.undefinedData().getAt(0, b.addr(0x4006));
@@ -281,7 +281,7 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
public void testGetProgram() throws CodeUnitInsertionException {
TraceInstruction i4004;
try (UndoableTransaction tid = b.startTransaction()) {
- i4004 = b.addInstruction(0, b.addr(0x4004), b.language, b.buf(0xf4, 0));
+ i4004 = b.addInstruction(0, b.addr(0x4004), null, b.buf(0xf4, 0));
}
assertEquals(0, i4004.getProgram().getSnap());
@@ -291,7 +291,7 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
public void testGetMemory() throws CodeUnitInsertionException {
TraceInstruction i4004;
try (UndoableTransaction tid = b.startTransaction()) {
- i4004 = b.addInstruction(0, b.addr(0x4004), b.language, b.buf(0xf4, 0));
+ i4004 = b.addInstruction(0, b.addr(0x4004), null, b.buf(0xf4, 0));
}
assertEquals(i4004.getProgram().getMemory(), i4004.getMemory());
@@ -300,14 +300,14 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
@Test
public void testIsBigEndian() throws CodeUnitInsertionException, AddressOverflowException {
Language x86 = getSLEIGH_X86_LANGUAGE();
- TraceGuestLanguage guest;
+ TraceGuestPlatform guest;
TraceInstruction i4004;
TraceInstruction g4006;
try (UndoableTransaction tid = b.startTransaction()) {
- i4004 = b.addInstruction(0, b.addr(0x4004), b.language, b.buf(0xf4, 0));
- guest = b.trace.getLanguageManager().addGuestLanguage(x86);
+ i4004 = b.addInstruction(0, b.addr(0x4004), null, b.buf(0xf4, 0));
+ guest = b.trace.getPlatformManager().addGuestPlatform(x86.getDefaultCompilerSpec());
guest.addMappedRange(b.addr(0x0000), b.addr(guest, 0x0000), 1L << 32);
- g4006 = b.addInstruction(0, b.addr(0x4006), x86, b.buf(0x90));
+ g4006 = b.addInstruction(0, b.addr(0x4006), guest, b.buf(0x90));
}
assertTrue(i4004.isBigEndian());
@@ -319,8 +319,8 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
TraceInstruction i4004;
TraceInstruction i4006;
try (UndoableTransaction tid = b.startTransaction()) {
- i4004 = b.addInstruction(0, b.addr(0x4004), b.language, b.buf(0xf4, 0));
- i4006 = b.addInstruction(0, b.addr(0x4006), b.language, b.buf(0xf4, 0));
+ i4004 = b.addInstruction(0, b.addr(0x4004), null, b.buf(0xf4, 0));
+ i4006 = b.addInstruction(0, b.addr(0x4006), null, b.buf(0xf4, 0));
}
assertFalse(i4004.hasProperty("myVoid"));
@@ -455,8 +455,8 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
TraceInstruction i4004;
TraceInstruction i4006;
try (UndoableTransaction tid = b.startTransaction()) {
- i4004 = b.addInstruction(0, b.addr(0x4004), b.language, b.buf(0xf4, 0));
- i4006 = b.addInstruction(0, b.addr(0x4006), b.language, b.buf(0xf4, 0));
+ i4004 = b.addInstruction(0, b.addr(0x4004), null, b.buf(0xf4, 0));
+ i4006 = b.addInstruction(0, b.addr(0x4006), null, b.buf(0xf4, 0));
}
try (UndoableTransaction tid = b.startTransaction()) {
@@ -510,7 +510,7 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
// TODO: Decide whether or not to shrink the comment lifespan with the unit lifespan
assertEquals(Range.atLeast(0L), c4004.getLifespan());
- i4004_10 = b.addInstruction(10, b.addr(0x4004), b.language);
+ i4004_10 = b.addInstruction(10, b.addr(0x4004), null);
i4004_10.setComment(CodeUnit.PRE_COMMENT, "Get this back in the mix");
i4004_10.setComment(CodeUnit.EOL_COMMENT, "A different comment");
}
@@ -538,8 +538,8 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
TraceInstruction i4006;
TraceData d4008;
try (UndoableTransaction tid = b.startTransaction()) {
- i4004 = b.addInstruction(0, b.addr(0x4004), b.language, b.buf(0xf4, 0));
- i4006 = b.addInstruction(0, b.addr(0x4006), b.language, b.buf(0xf4, 0));
+ i4004 = b.addInstruction(0, b.addr(0x4004), null, b.buf(0xf4, 0));
+ i4006 = b.addInstruction(0, b.addr(0x4006), null, b.buf(0xf4, 0));
d4008 = b.addData(0, b.addr(0x4008), LongDataType.dataType, b.buf(1, 2, 3, 4));
}
@@ -564,8 +564,8 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
TraceInstruction i4006;
try (UndoableTransaction tid = b.startTransaction()) {
d4000 = b.addData(0, b.addr(0x4000), LongDataType.dataType, b.buf(1, 2, 3, 4));
- i4004 = b.addInstruction(0, b.addr(0x4004), b.language, b.buf(0xf4, 0));
- i4006 = b.addInstruction(0, b.addr(0x4006), b.language, b.buf(0xf4, 0));
+ i4004 = b.addInstruction(0, b.addr(0x4004), null, b.buf(0xf4, 0));
+ i4006 = b.addInstruction(0, b.addr(0x4006), null, b.buf(0xf4, 0));
}
Set refs;
@@ -708,7 +708,7 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
TraceData undefined;
TraceData undReg;
try (UndoableTransaction tid = b.startTransaction()) {
- instruction = b.addInstruction(0, b.addr(0x4004), b.language, b.buf(0xf4, 0));
+ instruction = b.addInstruction(0, b.addr(0x4004), null, b.buf(0xf4, 0));
undefined = manager.undefinedData().getAt(0, b.addr(0x4006));
thread = b.getOrAddThread("Thread 1", 0);
@@ -739,7 +739,7 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
TraceInstruction i4004;
try (UndoableTransaction tid = b.startTransaction()) {
d4000 = b.addData(0, b.addr(0x4000), LongDataType.dataType, b.buf(1, 2, 3, 4));
- i4004 = b.addInstruction(0, b.addr(0x4004), b.language, b.buf(0xf4, 0));
+ i4004 = b.addInstruction(0, b.addr(0x4004), null, b.buf(0xf4, 0));
d4000.setEndSnap(9);
assertEquals(Range.closed(0L, 9L), d4000.getLifespan());
@@ -784,7 +784,7 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
@Test
public void testGetBytes() throws Exception {
Language x86 = getSLEIGH_X86_LANGUAGE();
- TraceGuestLanguage guest;
+ TraceGuestPlatform guest;
TraceData data;
TraceData und;
@@ -803,9 +803,9 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
DBTraceCodeRegisterSpace regCode = manager.getCodeRegisterSpace(thread, true);
reg = regCode.definedData().create(Range.atLeast(0L), r4, PointerDataType.dataType);
- guest = b.trace.getLanguageManager().addGuestLanguage(x86);
+ guest = b.trace.getPlatformManager().addGuestPlatform(x86.getDefaultCompilerSpec());
guest.addMappedRange(b.addr(0x0000), b.addr(guest, 0x0000), 1L << 32);
- lil = b.addInstruction(0, b.addr(0x4008), x86, b.buf(0xeb, 0xfe));
+ lil = b.addInstruction(0, b.addr(0x4008), guest, b.buf(0xeb, 0xfe));
}
ByteBuffer buf;
@@ -1039,13 +1039,13 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
.addRegion("myRegion", Range.atLeast(0L),
b.range(0x4000, 0x4fff), TraceMemoryFlag.READ);
- i4004 = b.addInstruction(0, b.addr(0x4004), b.language, b.buf(0xc8, 0x47));
+ i4004 = b.addInstruction(0, b.addr(0x4004), null, b.buf(0xc8, 0x47));
assertEquals("add r4,#0x7", i4004.toString());
- i4006 = b.addInstruction(0, b.addr(0x4006), b.language, b.buf(0xf4, 0));
+ i4006 = b.addInstruction(0, b.addr(0x4006), null, b.buf(0xf4, 0));
assertEquals("ret", i4006.toString());
- i4008 = b.addInstruction(0, b.addr(0x4008), b.language, b.buf(0xff, 0xfc));
+ i4008 = b.addInstruction(0, b.addr(0x4008), null, b.buf(0xff, 0xfc));
assertEquals("call 0x00004004", i4008.toString());
- i400a = b.addInstruction(0, b.addr(0x400a), b.language, b.buf(0xf6, 0x40));
+ i400a = b.addInstruction(0, b.addr(0x400a), null, b.buf(0xf6, 0x40));
assertEquals("call r4", i400a.toString());
}
@@ -1191,7 +1191,7 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
TraceInstruction i4004;
try (UndoableTransaction tid = b.startTransaction()) {
- i4004 = b.addInstruction(0, b.addr(0x4004), b.language, b.buf(0xf4, 0));
+ i4004 = b.addInstruction(0, b.addr(0x4004), null, b.buf(0xf4, 0));
}
// TODO: Test with non-default context
@@ -1240,7 +1240,7 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
TraceData d4006;
try (UndoableTransaction tid = b.startTransaction()) {
d4000 = b.addData(0, b.addr(0x4000), LongDataType.dataType, b.buf(1, 2, 3, 4));
- i4004 = b.addInstruction(0, b.addr(0x4004), b.language, b.buf(0xf4, 0));
+ i4004 = b.addInstruction(0, b.addr(0x4004), null, b.buf(0xf4, 0));
d4006 = b.addData(0, b.addr(0x4006), PointerDataType.dataType,
b.buf(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00));
}
@@ -1260,7 +1260,7 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
TraceData d4006;
try (UndoableTransaction tid = b.startTransaction()) {
d4000 = b.addData(0, b.addr(0x4000), LongDataType.dataType, b.buf(1, 2, 3, 4));
- i4004 = b.addInstruction(0, b.addr(0x4004), b.language, b.buf(0xf4, 0));
+ i4004 = b.addInstruction(0, b.addr(0x4004), null, b.buf(0xf4, 0));
d4006 = b.addData(0, b.addr(0x4006), PointerDataType.dataType,
b.buf(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00));
}
@@ -1285,14 +1285,14 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
@Test
public void testGetLanguage() throws CodeUnitInsertionException, AddressOverflowException {
Language x86 = getSLEIGH_X86_LANGUAGE();
- TraceGuestLanguage guest;
+ TraceGuestPlatform guest;
TraceInstruction i4004;
TraceInstruction g4006;
try (UndoableTransaction tid = b.startTransaction()) {
- i4004 = b.addInstruction(0, b.addr(0x4004), b.language, b.buf(0xf4, 0));
- guest = b.trace.getLanguageManager().addGuestLanguage(x86);
+ i4004 = b.addInstruction(0, b.addr(0x4004), null, b.buf(0xf4, 0));
+ guest = b.trace.getPlatformManager().addGuestPlatform(x86.getDefaultCompilerSpec());
guest.addMappedRange(b.addr(0x0000), b.addr(guest, 0x0000), 1L << 32);
- g4006 = b.addInstruction(0, b.addr(0x4006), x86, b.buf(0x90));
+ g4006 = b.addInstruction(0, b.addr(0x4006), guest, b.buf(0x90));
}
TraceData u4007 = manager.undefinedData().getAt(0, b.addr(0x4007));
@@ -1305,7 +1305,7 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
public void testToString() throws CodeUnitInsertionException, AddressOverflowException,
TraceOverlappedRegionException, DuplicateNameException {
Language x86 = getSLEIGH_X86_LANGUAGE();
- TraceGuestLanguage guest;
+ TraceGuestPlatform guest;
TraceData d4000;
TraceInstruction i4004;
TraceInstruction g4006;
@@ -1316,13 +1316,13 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
.addRegion("myRegion", Range.atLeast(0L),
b.range(0x4000, 0x4fff), TraceMemoryFlag.READ);
- guest = b.trace.getLanguageManager().addGuestLanguage(x86);
+ guest = b.trace.getPlatformManager().addGuestPlatform(x86.getDefaultCompilerSpec());
guest.addMappedRange(b.addr(0x0000), b.addr(guest, 0x0000), 1L << 32);
d4000 = b.addData(0, b.addr(0x4000), LongDataType.dataType, b.buf(1, 2, 3, 4));
- i4004 = b.addInstruction(0, b.addr(0x4004), b.language, b.buf(0xc8, 0x47));
- g4006 = b.addInstruction(0, b.addr(0x4006), x86, b.buf(0x90));
- i4007 = b.addInstruction(0, b.addr(0x4007), b.language, b.buf(0xff, 0xfd));
+ i4004 = b.addInstruction(0, b.addr(0x4004), null, b.buf(0xc8, 0x47));
+ g4006 = b.addInstruction(0, b.addr(0x4006), guest, b.buf(0x90));
+ i4007 = b.addInstruction(0, b.addr(0x4007), null, b.buf(0xff, 0xfd));
}
TraceData u4009 = manager.undefinedData().getAt(0, b.addr(0x4009));
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceDisassemblerIntegrationTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceDisassemblerIntegrationTest.java
index 14b1cecc00..a996c98fd8 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceDisassemblerIntegrationTest.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceDisassemblerIntegrationTest.java
@@ -35,7 +35,7 @@ import ghidra.program.model.listing.CodeUnit;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
import ghidra.trace.database.ToyDBTraceBuilder;
-import ghidra.trace.database.language.DBTraceGuestLanguage;
+import ghidra.trace.database.guest.DBTraceGuestPlatform;
import ghidra.trace.database.listing.*;
import ghidra.trace.database.memory.DBTraceMemoryManager;
import ghidra.trace.database.memory.DBTraceMemorySpace;
@@ -108,13 +108,15 @@ public class DBTraceDisassemblerIntegrationTest extends AbstractGhidraHeadlessIn
b.trace.getMemoryManager().getMemorySpace(b.language.getDefaultSpace(), true);
space.putBytes(0, b.addr(0x4000), b.buf(0x90));
- DBTraceGuestLanguage guest = b.trace.getLanguageManager().addGuestLanguage(x86);
+ DBTraceGuestPlatform guest =
+ b.trace.getPlatformManager().addGuestPlatform(x86.getDefaultCompilerSpec());
guest.addMappedRange(b.addr(0x4000), b.addr(guest, 0x00400000), 0x1000);
- // TODO: The more I look, the more I think I need a fully-mapped program view :(
- // As annoying as it is, I plan to do it as a wrapper, not as an extension....
- // The disassembler uses bookmarks, context, etc. for feedback. It'd be nice to
- // have that
+ /*
+ * TODO: The more I look, the more I think I need a fully-mapped program view :( As
+ * annoying as it is, I plan to do it as a wrapper, not as an extension.... The
+ * disassembler uses bookmarks, context, etc. for feedback. It'd be nice to have that.
+ */
RegisterValue defaultContextValue =
b.trace.getRegisterContextManager()
.getDefaultContext(x86)
@@ -125,7 +127,7 @@ public class DBTraceDisassemblerIntegrationTest extends AbstractGhidraHeadlessIn
guest.getMappedMemBuffer(0, b.addr(guest, 0x00400000)), defaultContextValue, 1));
DBTraceCodeManager code = b.trace.getCodeManager();
- code.instructions().addInstructionSet(Range.closed(0L, 0L), set, false);
+ code.instructions().addInstructionSet(Range.closed(0L, 0L), guest, set, false);
DBTraceInstruction ins = code.instructions().getAt(0, b.addr(0x4000));
// TODO: This is great, but probably incomplete.
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewListingTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewListingTest.java
index 09c5cbdd84..f341e8c209 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewListingTest.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewListingTest.java
@@ -114,7 +114,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra
CodeUnitInsertionException {
Instruction ins;
try (UndoableTransaction tid = b.startTransaction()) {
- ins = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
+ ins = b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
}
assertEquals("ret", ins.toString());
}
@@ -138,7 +138,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra
Instruction i4005;
try (UndoableTransaction tid = b.startTransaction()) {
- i4005 = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
+ i4005 = b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
}
assertEquals(i4005, listing.getCodeUnitAt(b.addr(0x4005)));
assertNull(listing.getCodeUnitAt(b.addr(0x4006)));
@@ -163,7 +163,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra
assertUndefined(listing.getCodeUnitContaining(b.addr(0x4005)));
Instruction i4005;
try (UndoableTransaction tid = b.startTransaction()) {
- i4005 = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
+ i4005 = b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
}
assertEquals(i4005, listing.getCodeUnitContaining(b.addr(0x4005)));
assertEquals(i4005, listing.getCodeUnitContaining(b.addr(0x4006)));
@@ -189,7 +189,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra
assertEquals(b.addr(0x4005), cu.getAddress());
Instruction i4005;
try (UndoableTransaction tid = b.startTransaction()) {
- i4005 = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
+ i4005 = b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
}
assertEquals(i4005, listing.getCodeUnitAfter(b.addr(0x4004)));
assertUndefined(cu = listing.getCodeUnitAfter(b.addr(0x4005)));
@@ -215,7 +215,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra
assertEquals(b.addr(0x4005), cu.getAddress());
Instruction i4005;
try (UndoableTransaction tid = b.startTransaction()) {
- i4005 = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
+ i4005 = b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
}
assertEquals(i4005, listing.getCodeUnitBefore(b.addr(0x4006)));
assertUndefined(cu = listing.getCodeUnitBefore(b.addr(0x4005)));
@@ -291,7 +291,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra
Instruction i4005;
try (UndoableTransaction tid = b.startTransaction()) {
d4000 = b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4));
- i4005 = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
+ i4005 = b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
}
sample = takeN(10, listing.getCodeUnits(true));
@@ -355,7 +355,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra
assertNull(listing.getInstructionAt(b.addr(0x4005)));
Instruction i4005;
try (UndoableTransaction tid = b.startTransaction()) {
- i4005 = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
+ i4005 = b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
}
assertEquals(i4005, listing.getInstructionAt(b.addr(0x4005)));
assertNull(listing.getInstructionAt(b.addr(0x4006)));
@@ -368,7 +368,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra
assertNull(listing.getInstructionContaining(b.addr(0x4005)));
Instruction i4005;
try (UndoableTransaction tid = b.startTransaction()) {
- i4005 = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
+ i4005 = b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
}
assertEquals(i4005, listing.getInstructionContaining(b.addr(0x4005)));
assertEquals(i4005, listing.getInstructionContaining(b.addr(0x4006)));
@@ -381,7 +381,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra
assertNull(listing.getInstructionAfter(b.addr(0x4004)));
Instruction i4005;
try (UndoableTransaction tid = b.startTransaction()) {
- i4005 = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
+ i4005 = b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
}
assertEquals(i4005, listing.getInstructionAfter(b.addr(0x4004)));
assertNull(listing.getInstructionAfter(b.addr(0x4005)));
@@ -393,7 +393,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra
assertNull(listing.getInstructionBefore(b.addr(0x4006)));
Instruction i4005;
try (UndoableTransaction tid = b.startTransaction()) {
- i4005 = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
+ i4005 = b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
}
assertEquals(i4005, listing.getInstructionBefore(b.addr(0x4006)));
assertNull(listing.getInstructionBefore(b.addr(0x4005)));
@@ -421,9 +421,9 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra
Instruction i4007;
Instruction i400a;
try (UndoableTransaction tid = b.startTransaction()) {
- i4005 = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
- i4007 = b.addInstruction(0, b.addr(0x4007), b.language, b.buf(0xf4, 0));
- i400a = b.addInstruction(0, b.addr(0x400a), b.language, b.buf(0xf4, 0));
+ i4005 = b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
+ i4007 = b.addInstruction(0, b.addr(0x4007), null, b.buf(0xf4, 0));
+ i400a = b.addInstruction(0, b.addr(0x400a), null, b.buf(0xf4, 0));
b.addData(0, b.addr(0x400c), Undefined4DataType.dataType, b.buf(1, 2, 3, 4));
}
@@ -454,7 +454,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra
assertUndefined(listing.getDataAt(b.addr(0x4005)));
try (UndoableTransaction tid = b.startTransaction()) {
- b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
+ b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
}
assertNull(listing.getDataAt(b.addr(0x4005)));
assertNull(listing.getDataAt(b.addr(0x4006)));
@@ -477,7 +477,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra
assertUndefined(listing.getDataContaining(b.addr(0x4005)));
try (UndoableTransaction tid = b.startTransaction()) {
- b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
+ b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
}
assertNull(listing.getDataContaining(b.addr(0x4005)));
assertNull(listing.getDataContaining(b.addr(0x4006)));
@@ -502,7 +502,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra
assertUndefined(cu = listing.getDataAfter(b.addr(0x4004)));
assertEquals(b.addr(0x4005), cu.getAddress());
try (UndoableTransaction tid = b.startTransaction()) {
- b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
+ b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
}
assertUndefined(cu = listing.getDataAfter(b.addr(0x4004)));
assertEquals(b.addr(0x4007), cu.getAddress());
@@ -526,7 +526,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra
assertUndefined(cu = listing.getDataBefore(b.addr(0x4006)));
assertEquals(b.addr(0x4005), cu.getAddress());
try (UndoableTransaction tid = b.startTransaction()) {
- b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
+ b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
}
assertUndefined(cu = listing.getDataBefore(b.addr(0x4007)));
assertEquals(b.addr(0x4004), cu.getAddress());
@@ -600,7 +600,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra
Data d4000;
try (UndoableTransaction tid = b.startTransaction()) {
d4000 = b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4));
- b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
+ b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
}
sample = takeN(10, listing.getData(true));
@@ -731,7 +731,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra
d4004 = b.addData(0, b.addr(0x4004), Undefined4DataType.dataType, b.buf(5, 6, 7, 8));
d400a =
b.addData(0, b.addr(0x400a), Undefined4DataType.dataType, b.buf(10, 11, 12, 13));
- b.addInstruction(0, b.addr(0x400e), b.language, b.buf(0xf4, 0));
+ b.addInstruction(0, b.addr(0x400e), null, b.buf(0xf4, 0));
}
assertEquals(List.of(d4000, d4004, d400a), takeN(10, listing.getDefinedData(true)));
@@ -760,7 +760,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra
assertUndefined(listing.getUndefinedDataAt(b.addr(0x4005)));
try (UndoableTransaction tid = b.startTransaction()) {
- b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
+ b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
}
assertNull(listing.getUndefinedDataAt(b.addr(0x4005)));
assertNull(listing.getUndefinedDataAt(b.addr(0x4006)));
@@ -783,7 +783,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra
assertUndefined(cu = listing.getUndefinedDataAfter(b.addr(0x4004), TaskMonitor.DUMMY));
assertEquals(b.addr(0x4005), cu.getAddress());
try (UndoableTransaction tid = b.startTransaction()) {
- b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
+ b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
}
assertUndefined(cu = listing.getUndefinedDataAfter(b.addr(0x4004), TaskMonitor.DUMMY));
assertEquals(b.addr(0x4007), cu.getAddress());
@@ -805,7 +805,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra
assertUndefined(cu = listing.getUndefinedDataBefore(b.addr(0x4006), TaskMonitor.DUMMY));
assertEquals(b.addr(0x4005), cu.getAddress());
try (UndoableTransaction tid = b.startTransaction()) {
- b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
+ b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
}
assertUndefined(cu = listing.getUndefinedDataBefore(b.addr(0x4007), TaskMonitor.DUMMY));
assertEquals(b.addr(0x4004), cu.getAddress());
@@ -816,7 +816,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra
UnknownInstructionException, CodeUnitInsertionException {
try (UndoableTransaction tid = b.startTransaction()) {
b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4));
- b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
+ b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
}
Data cu;
@@ -834,7 +834,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra
UnknownInstructionException, CodeUnitInsertionException, CancelledException {
try (UndoableTransaction tid = b.startTransaction()) {
b.addData(0, b.addr(0x4000), Undefined4DataType.dataType, b.buf(1, 2, 3, 4));
- b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
+ b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
}
TODO(); // Should I expect OTHER ranges in the undefined set?
@@ -849,7 +849,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra
assertNull(listing.getDefinedCodeUnitAfter(b.addr(0x3fff)));
Instruction i4005;
try (UndoableTransaction tid = b.startTransaction()) {
- i4005 = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
+ i4005 = b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
}
assertEquals(i4005, listing.getDefinedCodeUnitAfter(b.addr(0x3fff)));
assertNull(listing.getDefinedCodeUnitAfter(b.addr(0x4005)));
@@ -873,7 +873,7 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra
assertNull(listing.getDefinedCodeUnitBefore(b.addr(0x4000)));
Instruction i4005;
try (UndoableTransaction tid = b.startTransaction()) {
- i4005 = b.addInstruction(0, b.addr(0x4005), b.language, b.buf(0xf4, 0));
+ i4005 = b.addInstruction(0, b.addr(0x4005), null, b.buf(0xf4, 0));
}
assertEquals(i4005, listing.getDefinedCodeUnitBefore(b.addr(0x4006)));
assertEquals(d4000, listing.getDefinedCodeUnitBefore(b.addr(0x4005)));
diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/framework/cmd/TypedBackgroundCommand.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/framework/cmd/TypedBackgroundCommand.java
new file mode 100644
index 0000000000..b5ff519b3b
--- /dev/null
+++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/framework/cmd/TypedBackgroundCommand.java
@@ -0,0 +1,42 @@
+/* ###
+ * 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.framework.cmd;
+
+import ghidra.framework.model.DomainObject;
+import ghidra.framework.model.UndoableDomainObject;
+import ghidra.framework.plugintool.PluginTool;
+import ghidra.util.task.TaskMonitor;
+
+public abstract class TypedBackgroundCommand
+ extends BackgroundCommand {
+
+ public TypedBackgroundCommand(String name, boolean hasProgress, boolean canCancel,
+ boolean isModal) {
+ super(name, hasProgress, canCancel, isModal);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
+ return applyToTyped((T) obj, monitor);
+ }
+
+ public abstract boolean applyToTyped(T obj, TaskMonitor monitor);
+
+ public void run(PluginTool tool, T obj) {
+ tool.executeBackgroundCommand(this, obj);
+ }
+}
diff --git a/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java b/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java
index 18b0d44d76..a89c66c022 100644
--- a/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java
+++ b/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java
@@ -266,7 +266,8 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
}
/**
- * Returns a new list of all DockingWindowManager instances know to exist.
+ * Returns a new list of all DockingWindowManager instances known to exist, ordered from least
+ * to most-recently active.
*
* @return a new list of all DockingWindowManager instances know to exist.
*/
diff --git a/Ghidra/Processors/Toy/certification.manifest b/Ghidra/Processors/Toy/certification.manifest
index c9e9252d33..0e477e8798 100644
--- a/Ghidra/Processors/Toy/certification.manifest
+++ b/Ghidra/Processors/Toy/certification.manifest
@@ -14,6 +14,7 @@ data/languages/toy.cspec||GHIDRA||||END|
data/languages/toy.ldefs||GHIDRA||||END|
data/languages/toy.pspec||GHIDRA||reviewed||END|
data/languages/toy.sinc||GHIDRA||||END|
+data/languages/toy64-long8.cspec||GHIDRA||||END|
data/languages/toy64.cspec||GHIDRA||||END|
data/languages/toy64_be.slaspec||GHIDRA||||END|
data/languages/toy64_be_harvard.slaspec||GHIDRA||||END|
diff --git a/Ghidra/Processors/Toy/data/languages/toy.ldefs b/Ghidra/Processors/Toy/data/languages/toy.ldefs
index 530b23ab5c..7bd3ec76cd 100644
--- a/Ghidra/Processors/Toy/data/languages/toy.ldefs
+++ b/Ghidra/Processors/Toy/data/languages/toy.ldefs
@@ -66,6 +66,7 @@
id="Toy:BE:64:default">
Toy (test) processor 64-bit big-endian
+