diff --git a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/app/services/DebuggerPlatformService.java b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/app/services/DebuggerPlatformService.java
index b7957732b6..0cf60bc3e6 100644
--- a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/app/services/DebuggerPlatformService.java
+++ b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/app/services/DebuggerPlatformService.java
@@ -4,9 +4,9 @@
* 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.
@@ -65,9 +65,11 @@ public interface DebuggerPlatformService {
/**
* Set the current mapper for the trace and initialize the trace for the mapper
*
- * @param trace the trace whose current mapper to set
+ * @param trace the trace whose mapper to assign and initialize
+ * @param focus the object of focus
* @param mapper the mapper
* @param snap the snap for initializing the trace
*/
- void setCurrentMapperFor(Trace trace, DebuggerPlatformMapper mapper, long snap);
+ void setCurrentMapperFor(Trace trace, TraceObject focus, DebuggerPlatformMapper mapper,
+ long snap);
}
diff --git a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/platform/DebuggerPlatformMapper.java b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/platform/DebuggerPlatformMapper.java
index 8bc98f69c1..3d9deb683d 100644
--- a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/platform/DebuggerPlatformMapper.java
+++ b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/platform/DebuggerPlatformMapper.java
@@ -4,9 +4,9 @@
* 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.
@@ -19,12 +19,40 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.lang.Language;
+import ghidra.program.model.listing.Program;
+import ghidra.trace.model.guest.TracePlatform;
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
+ *
+ *
+ * Platform selection is a bit of a work in progress, but the idea is to allow the mapper to choose
+ * relevant languages, compiler specifications, data organization, etc., based on the current
+ * debugger context. Most of these are fairly straightforward and relatively static. If the back-end
+ * creates the trace with an actual language (non-DATA), then there's a default mapper for "known
+ * hosts," (but this can be out prioritized by more complex mappers). If the back-end creates a
+ * trace with a DATA language (usually indicating it doesn't recognize the target architecture),
+ * then some pluggable examine the name of the debugger and its reported architecture to try to map
+ * it on the front end. There may not be any good opinions, in which case, the user can override
+ * with any language. That's the "simple" cases.
+ *
+ *
+ * In more complex cases, e.g., WoW64, the mapper may need to adjust the recommended language based
+ * on, e.g., the current program counter and loaded modules. Essentially, it must determine the CPUs
+ * current ISA mode and adjust accordingly. There are currently two known situations: 1)
+ * Disassembly, and 2) Data (namely pointer) Organization, controlled by the Compiler Spec. The
+ * selection logic differs slightly between the two. For disassembly, we allow the mapper specific
+ * control of the selected platform, based on the starting address. For data placement, we allow the
+ * mapper specific control of the selected platform, based on the current PC. Note that the starting
+ * address of the data itself may not always be relevant. At the moment, because of limitations in
+ * the {@link Program} API, we actually cannot support selection based on placement address.
+ * Instead, at the time we ask the mapper to add a platform to the trace
+ * ({@link #addToTrace(TraceObject, long)}), we provide the current focus and snap, so that it can
+ * derive the PC or whatever other context is necessary to make its decision. The returned platform
+ * is immediately set as current, so that data actions heed the chosen platform.
*/
public interface DebuggerPlatformMapper {
@@ -32,18 +60,20 @@ public interface DebuggerPlatformMapper {
* Get the compiler for a given object
*
* @param object the object
+ * @param snap the snap
* @return the compiler spec
*/
- CompilerSpec getCompilerSpec(TraceObject object);
+ CompilerSpec getCompilerSpec(TraceObject object, long snap);
/**
* Get the language for a given object
*
* @param object the object
+ * @param snap the snap
* @return the language
*/
- default Language getLangauge(TraceObject object) {
- CompilerSpec cSpec = getCompilerSpec(object);
+ default Language getLangauge(TraceObject object, long snap) {
+ CompilerSpec cSpec = getCompilerSpec(object, snap);
return cSpec == null ? null : cSpec.getLanguage();
}
@@ -54,10 +84,11 @@ public interface DebuggerPlatformMapper {
* Likely, this will need to modify the trace database. It must start its own transaction for
* doing so.
*
- * @param trace the trace
+ * @param newFocus the newly-focused object
* @param snap the snap
+ * @return the resulting platform, which may have already existed
*/
- void addToTrace(long snap);
+ TracePlatform addToTrace(TraceObject newFocus, long snap);
/**
* When focus changes, decide if this mapper should remain active
@@ -71,6 +102,10 @@ public interface DebuggerPlatformMapper {
/**
* Disassemble starting at a given address and snap, limited to a given address set
*
+ *
+ * Note that the mapper may use an alternative platform than that returned by
+ * {@link #addToTrace(TraceObject, long)}.
+ *
* @param thread the thread if applicable
* @param object the object for platform context
* @param start the starting address
diff --git a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/tracemgr/DebuggerCoordinates.java b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/tracemgr/DebuggerCoordinates.java
index b7e5265cf0..fb71267384 100644
--- a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/tracemgr/DebuggerCoordinates.java
+++ b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/tracemgr/DebuggerCoordinates.java
@@ -128,13 +128,15 @@ public class DebuggerCoordinates {
@Override
public boolean equals(Object obj) {
- if (!(obj instanceof DebuggerCoordinates)) {
+ if (!(obj instanceof DebuggerCoordinates that)) {
return false;
}
- DebuggerCoordinates that = (DebuggerCoordinates) obj;
if (!Objects.equals(this.trace, that.trace)) {
return false;
}
+ if (!Objects.equals(this.platform, that.platform)) {
+ return false;
+ }
if (!Objects.equals(this.target, that.target)) {
return false;
}
@@ -436,7 +438,6 @@ public class DebuggerCoordinates {
if (!Objects.equals(this.trace, that.trace)) {
return false;
}
-
if (!Objects.equals(this.platform, that.platform)) {
return false;
}
diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/client.py b/Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/client.py
index b78b251376..90787214d7 100644
--- a/Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/client.py
+++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/client.py
@@ -1376,8 +1376,9 @@ class Receiver(Thread):
Client._write_value(
reply.xreply_invoke_method.return_value, result)
except BaseException as e:
- print("Error caused by front end")
- traceback.print_exc()
+ print(f"Error caused by front end: {e}")
+ # TODO: Add a field to error for stacktrace, log it at front-end
+ # traceback.print_exc()
reply.xreply_invoke_method.error = repr(e)
self.client._send(reply)
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/platform/DebuggerPlatformPlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/platform/DebuggerPlatformPlugin.java
index a7f79e2a08..e047f7726b 100644
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/platform/DebuggerPlatformPlugin.java
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/platform/DebuggerPlatformPlugin.java
@@ -4,9 +4,9 @@
* 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.
@@ -75,7 +75,7 @@ public class DebuggerPlatformPlugin extends Plugin {
}
}
- protected interface ChooseMorePlatformsActon {
+ protected interface ChooseMorePlatformsAction {
String NAME = DebuggerResources.NAME_CHOOSE_MORE_PLATFORMS;
String TITLE = DebuggerResources.TITLE_CHOOSE_MORE_PLATFORMS;
String DESCRIPTION = DebuggerResources.DESCRIPTION_CHOOSE_MORE_PLATFORMS;
@@ -92,28 +92,13 @@ public class DebuggerPlatformPlugin extends Plugin {
}
}
- protected static boolean sameCoordinates(DebuggerCoordinates a, DebuggerCoordinates b) {
- if (!Objects.equals(a.getTrace(), b.getTrace())) {
- return false;
- }
- if (!Objects.equals(a.getTime(), b.getTime())) {
- return false;
- }
- if (!Objects.equals(a.getObject(), b.getObject())) {
- return false;
- }
- return true;
- }
-
protected class PlatformActionSet {
private final Trace trace;
- private DebuggerCoordinates current;
private final Map actions =
new LinkedHashMap<>();
public PlatformActionSet(Trace trace) {
this.trace = trace;
- this.current = traceManager.getCurrentFor(trace);
}
protected Set computePlatformOffers(boolean includeOverrides) {
@@ -126,15 +111,16 @@ public class DebuggerPlatformPlugin extends Plugin {
ToggleDockingAction action = ChoosePlatformAction.builder(DebuggerPlatformPlugin.this)
.menuPath(DebuggerPluginPackage.NAME, ChoosePlatformAction.NAME,
offer.getDescription())
- .onAction(ctx -> activatePlatform(offer))
+ .onAction(ctx -> activatePlatformOffer(offer))
.build();
String[] path = action.getMenuBarData().getMenuPath();
tool.setMenuGroup(Arrays.copyOf(path, path.length - 1), ChoosePlatformAction.GROUP);
return action;
}
- protected void activatePlatform(DebuggerPlatformOffer offer) {
- platformService.setCurrentMapperFor(trace, offer.take(tool, trace), current.getSnap());
+ protected void activatePlatformOffer(DebuggerPlatformOffer offer) {
+ platformService.setCurrentMapperFor(trace, current.getObject(), offer.take(tool, trace),
+ current.getSnap());
}
protected void cleanOffers() {
@@ -159,7 +145,7 @@ public class DebuggerPlatformPlugin extends Plugin {
protected void addChosenOffer(DebuggerPlatformOffer offer) {
ToggleDockingAction action = addOfferAction(offer);
// NB. PluginEvent will cause selections to update
- if (currentTrace == trace) {
+ if (current.getTrace() == trace) {
tool.addAction(action);
}
}
@@ -176,15 +162,6 @@ public class DebuggerPlatformPlugin extends Plugin {
}
}
- protected void coordinatesActivated(DebuggerCoordinates coordinates) {
- if (sameCoordinates(current, coordinates)) {
- current = coordinates;
- return;
- }
- current = coordinates;
- updatePlatformOffers();
- }
-
protected void mapperActivated(DebuggerPlatformMapper mapper) {
for (Entry ent : actions.entrySet()) {
DebuggerPlatformOffer offer = ent.getKey();
@@ -201,7 +178,7 @@ public class DebuggerPlatformPlugin extends Plugin {
@SuppressWarnings("unused")
private final Wiring autoServiceWiring;
- private Trace currentTrace;
+ private DebuggerCoordinates current = DebuggerCoordinates.NOWHERE;
private final ChangeListener classChangeListener = evt -> this.classesChanged();
@@ -221,18 +198,19 @@ public class DebuggerPlatformPlugin extends Plugin {
}
protected void installActions() {
- if (currentTrace == null) {
+ Trace trace = current.getTrace();
+ if (trace == null) {
return;
}
PlatformActionSet actions =
- actionsChoosePlatform.computeIfAbsent(currentTrace, PlatformActionSet::new);
+ actionsChoosePlatform.computeIfAbsent(trace, PlatformActionSet::new);
actions.updatePlatformOffers();
- actions.mapperActivated(platformService.getCurrentMapperFor(currentTrace));
+ actions.mapperActivated(platformService.getCurrentMapperFor(trace));
actions.installActions();
}
protected void uninstallActions() {
- PlatformActionSet actions = actionsChoosePlatform.get(currentTrace);
+ PlatformActionSet actions = actionsChoosePlatform.get(current.getTrace());
if (actions != null) {
actions.uninstallActions();
}
@@ -240,8 +218,8 @@ public class DebuggerPlatformPlugin extends Plugin {
protected void createActions() {
installActions();
- actionMore = ChooseMorePlatformsActon.builder(this)
- .enabledWhen(ctx -> currentTrace != null)
+ actionMore = ChooseMorePlatformsAction.builder(this)
+ .enabledWhen(ctx -> current.getTrace() != null)
.onAction(this::activatedChooseMore)
.buildAndInstall(tool);
String[] path = actionMore.getMenuBarData().getMenuPath();
@@ -254,13 +232,11 @@ public class DebuggerPlatformPlugin extends Plugin {
// Still initializing or finalizing
return;
}
- // Sort of a backwards way to retrieve the current coordinates....
- PlatformActionSet actions = actionsChoosePlatform.get(currentTrace);
+ Trace trace = current.getTrace();
+ PlatformActionSet actions = actionsChoosePlatform.get(trace);
if (actions == null) {
return;
}
- DebuggerCoordinates current = actions.current;
- Trace trace = current.getTrace();
TraceObject object = current.getObject();
long snap = current.getSnap();
@@ -268,7 +244,7 @@ public class DebuggerPlatformPlugin extends Plugin {
// Dialog allows Swing to do other things, so re-check platformService
if (offer != null && platformService != null) {
actions.addChosenOffer(offer);
- platformService.setCurrentMapperFor(trace, offer.take(tool, trace), snap);
+ platformService.setCurrentMapperFor(trace, object, offer.take(tool, trace), snap);
// NOTE: DebuggerPlatformPluginEvent will cause selection change
}
}
@@ -282,21 +258,24 @@ public class DebuggerPlatformPlugin extends Plugin {
}
protected void coordinatesActivated(DebuggerCoordinates coordinates) {
+ if (Objects.equals(current, coordinates)) {
+ return;
+ }
uninstallActions();
- this.currentTrace = coordinates.getTrace();
+ this.current = coordinates;
installActions();
tool.contextChanged(null);
}
protected void traceClosed(Trace trace) {
- if (trace == currentTrace) {
+ if (trace == current.getTrace()) {
coordinatesActivated(DebuggerCoordinates.NOWHERE);
}
actionsChoosePlatform.remove(trace);
}
protected void mapperActivated(Trace trace, DebuggerPlatformMapper mapper) {
- if (trace != currentTrace) {
+ if (trace != current.getTrace()) {
return;
}
PlatformActionSet actions = actionsChoosePlatform.get(trace);
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
index 61c2340c20..3674d2c27f 100644
--- 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
@@ -17,7 +17,6 @@ package ghidra.app.plugin.core.debug.mapping;
import java.util.Collection;
import java.util.Comparator;
-import java.util.Map.Entry;
import java.util.stream.Collectors;
import ghidra.app.plugin.core.debug.disassemble.DisassemblyInject;
@@ -28,7 +27,6 @@ import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.Endian;
import ghidra.trace.model.Trace;
-import ghidra.trace.model.TraceAddressSnapRange;
import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.listing.TraceInstruction;
import ghidra.trace.model.memory.TraceMemoryOperations;
@@ -75,6 +73,10 @@ public abstract class AbstractDebuggerPlatformMapper implements DebuggerPlatform
TraceMemoryState.KNOWN);
}
+ protected TracePlatform getDisassemblyPlatform(TraceObject object, Address start, long snap) {
+ return trace.getPlatformManager().getPlatform(getCompilerSpec(object, snap));
+ }
+
protected Collection getDisassemblyInjections(TracePlatform platform) {
return ClassSearcher.getInstances(DisassemblyInject.class)
.stream()
@@ -89,8 +91,8 @@ public abstract class AbstractDebuggerPlatformMapper implements DebuggerPlatform
if (isCancelSilently(start, snap)) {
return DisassemblyResult.CANCELLED;
}
- TracePlatform platform = trace.getPlatformManager().getPlatform(getCompilerSpec(object));
+ TracePlatform platform = getDisassemblyPlatform(object, start, snap);
Collection injects = getDisassemblyInjections(platform);
TraceDisassembleCommand dis = new TraceDisassembleCommand(platform, start, restricted);
AddressSet startSet = new AddressSet(start);
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
index 3a8bc05668..2e5505839b 100644
--- 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
@@ -4,9 +4,9 @@
* 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.
@@ -49,24 +49,28 @@ public class DefaultDebuggerPlatformMapper extends AbstractDebuggerPlatformMappe
}
@Override
- public CompilerSpec getCompilerSpec(TraceObject object) {
+ public CompilerSpec getCompilerSpec(TraceObject object, long snap) {
return cSpec;
}
- @Override
- public void addToTrace(long snap) {
+ protected TracePlatform addOrGetPlatform(CompilerSpec cSpec, long snap) {
String description = "Add guest " + cSpec.getLanguage().getLanguageDescription() + "/" +
cSpec.getCompilerSpecDescription();
try (Transaction tx = trace.openTransaction(description)) {
TracePlatformManager platformManager = trace.getPlatformManager();
TracePlatform platform = platformManager.getOrAddPlatform(cSpec);
- if (platform.isHost()) {
- return;
+ if (!platform.isHost()) {
+ addMappedRanges((TraceGuestPlatform) platform);
}
- addMappedRanges((TraceGuestPlatform) platform);
+ return platform;
}
}
+ @Override
+ public TracePlatform addToTrace(TraceObject newFocus, long snap) {
+ return addOrGetPlatform(cSpec, snap);
+ }
+
/**
* Add mapped ranges if not already present
*
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/HostDebuggerPlatformOpinion.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/HostDebuggerPlatformOpinion.java
index 4f3fd29ef8..a5289f32b9 100644
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/HostDebuggerPlatformOpinion.java
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/HostDebuggerPlatformOpinion.java
@@ -22,6 +22,7 @@ import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.lang.Processor;
import ghidra.trace.model.Trace;
+import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.target.TraceObject;
/**
@@ -30,6 +31,8 @@ import ghidra.trace.model.target.TraceObject;
* the real language must be mapped as a guest platform.
*/
public class HostDebuggerPlatformOpinion implements DebuggerPlatformOpinion {
+ // An alternative default had better mean it.
+ public static final int CONFIDENCE_HOST_KNOWN = 10000;
protected static class HostDebuggerPlatformMapper extends AbstractDebuggerPlatformMapper {
public HostDebuggerPlatformMapper(PluginTool tool, Trace trace) {
@@ -37,13 +40,13 @@ public class HostDebuggerPlatformOpinion implements DebuggerPlatformOpinion {
}
@Override
- public CompilerSpec getCompilerSpec(TraceObject object) {
+ public CompilerSpec getCompilerSpec(TraceObject object, long snap) {
return trace.getBaseCompilerSpec();
}
@Override
- public void addToTrace(long snap) {
- // Nothing to do
+ public TracePlatform addToTrace(TraceObject newFocus, long snap) {
+ return trace.getPlatformManager().getHostPlatform();
}
@Override
@@ -79,7 +82,7 @@ public class HostDebuggerPlatformOpinion implements DebuggerPlatformOpinion {
@Override
public int getConfidence() {
- return 10000; // An alternative default had better mean it. Really.
+ return CONFIDENCE_HOST_KNOWN;
}
};
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
index e56248a251..46affd815f 100644
--- 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
@@ -4,9 +4,9 @@
* 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.
@@ -15,47 +15,166 @@
*/
package ghidra.app.plugin.core.debug.platform.dbgeng;
+import java.io.IOException;
import java.util.Collection;
import java.util.Set;
+import java.util.concurrent.*;
+import java.util.stream.Collectors;
import ghidra.app.plugin.core.debug.disassemble.DisassemblyInject;
+import ghidra.app.plugin.core.debug.gui.action.PCLocationTrackingSpec;
import ghidra.app.plugin.core.debug.mapping.*;
+import ghidra.app.services.DebuggerTargetService;
+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.debug.api.platform.DebuggerPlatformMapper;
+import ghidra.debug.api.target.Target;
+import ghidra.debug.api.tracemgr.DebuggerCoordinates;
import ghidra.framework.plugintool.PluginTool;
+import ghidra.program.model.address.Address;
+import ghidra.program.model.address.AddressSet;
import ghidra.program.model.lang.*;
+import ghidra.program.model.mem.MemBuffer;
import ghidra.trace.model.Trace;
import ghidra.trace.model.guest.TracePlatform;
+import ghidra.trace.model.modules.TraceModule;
import ghidra.trace.model.target.TraceObject;
+import ghidra.util.Msg;
+import ghidra.util.task.TaskMonitor;
public class DbgengDebuggerPlatformOpinion extends AbstractDebuggerPlatformOpinion {
protected static final LanguageID LANG_ID_X86_64 = new LanguageID("x86:LE:64:default");
+ protected static final LanguageID LANG_ID_X86_64_32 = new LanguageID("x86:LE:64:compat32");
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) {
+ enum Mode {
+ X64, X86, UNK;
+
+ static Mode computeFor(PluginTool tool, Trace trace, Address address, long snap) {
+ DebuggerTargetService targetService = tool.getService(DebuggerTargetService.class);
+ Target target = targetService == null ? null : targetService.getTarget(trace);
+ Collection extends TraceModule> modules =
+ trace.getModuleManager().getModulesAt(snap, address);
+ Msg.debug(Mode.class, "Disassembling in modules: " +
+ modules.stream().map(m -> m.getName(snap)).collect(Collectors.joining(",")));
+ Set modes = modules.stream()
+ .map(m -> modeForModule(target, trace, snap, m))
+ .filter(m -> m != UNK)
+ .collect(Collectors.toSet());
+ Msg.debug(Mode.class, "Disassembling in mode(s): " + modes);
+ if (modes.size() != 1) {
+ return UNK;
+ }
+ return modes.iterator().next();
+ }
+
+ static Mode modeForModule(Target target, Trace trace, long snap, TraceModule module) {
+ if (target != null && target.getSnap() == snap) {
+ AddressSet set = new AddressSet();
+ set.add(module.getBase(snap), module.getBase(snap)); // Recorder should read page
+ try {
+ target.readMemoryAsync(set, TaskMonitor.DUMMY).get(1, TimeUnit.SECONDS);
+ trace.flushEvents();
+ }
+ catch (InterruptedException | ExecutionException | TimeoutException e) {
+ throw new AssertionError(e);
+ }
+ }
+ MemBuffer bufferAt = trace.getMemoryManager().getBufferAt(snap, module.getBase(snap));
+ try (ByteProvider bp = new MemBufferByteProvider(bufferAt)) {
+ PortableExecutable pe =
+ new PortableExecutable(bp, SectionLayout.MEMORY, false, false);
+ NTHeader ntHeader = pe.getNTHeader();
+ if (ntHeader == null) {
+ return UNK;
+ }
+ OptionalHeader optionalHeader = ntHeader.getOptionalHeader();
+ if (optionalHeader == null) {
+ return UNK; // Really shouldn't happen, but who knows?
+ }
+ return optionalHeader.is64bit() ? X64 : X86;
+ }
+ catch (IOException e) {
+ Msg.warn(Mode.class, "Could not parse PE from trace: " + e);
+ return UNK;
+ }
+ }
+ }
+
+ protected abstract static class AbstractDbgengX64DebuggerPlatformMapper
+ extends DefaultDebuggerPlatformMapper {
+ public AbstractDbgengX64DebuggerPlatformMapper(PluginTool tool, Trace trace,
+ CompilerSpec cSpec) {
super(tool, trace, cSpec);
}
// TODO: Map registers: efl,rfl,rflags->eflags
+ @Override
+ protected TracePlatform getDisassemblyPlatform(TraceObject object, Address start,
+ long snap) {
+ CompilerSpec x64cs = Offer.X64.getCompilerSpec();
+ return addOrGetPlatform(x64cs, snap);
+ }
+
@Override
protected Collection getDisassemblyInjections(TracePlatform platform) {
return INJECTS;
}
}
- enum Offers implements DebuggerPlatformOffer {
+ protected static class DbgengX64DebuggerPlatformMapper
+ extends AbstractDbgengX64DebuggerPlatformMapper {
+ public DbgengX64DebuggerPlatformMapper(PluginTool tool, Trace trace,
+ CompilerSpec cSpec) {
+ super(tool, trace, cSpec);
+ }
+ }
+
+ protected static class DbgengX64_32DebuggerPlatformMapper
+ extends AbstractDbgengX64DebuggerPlatformMapper {
+ public DbgengX64_32DebuggerPlatformMapper(PluginTool tool, Trace trace,
+ CompilerSpec cSpec) {
+ super(tool, trace, cSpec);
+ }
+ }
+
+ protected static class DbgengWoW64DebuggerPlatformMapper
+ extends AbstractDbgengX64DebuggerPlatformMapper {
+ public DbgengWoW64DebuggerPlatformMapper(PluginTool tool, Trace trace,
+ CompilerSpec cSpec) {
+ super(tool, trace, cSpec);
+ }
+
+ @Override
+ public TracePlatform addToTrace(TraceObject newFocus, long snap) {
+ DebuggerCoordinates coords = DebuggerCoordinates.NOWHERE.object(newFocus).snap(snap);
+ Address pc = PCLocationTrackingSpec.INSTANCE.computeTraceAddress(tool, coords);
+ if (pc == null) {
+ return addOrGetPlatform(Offer.X64_32.getCompilerSpec(), snap);
+ }
+ Offer sel = switch (Mode.computeFor(tool, trace, pc, snap)) {
+ case X64 -> Offer.X64;
+ default -> Offer.X64_32;
+ };
+ return addOrGetPlatform(sel.getCompilerSpec(), snap);
+ }
+ }
+
+ enum Offer implements DebuggerPlatformOffer {
// TODO: X86?
X64 {
@Override
public String getDescription() {
- return "Dbgeng on Windows x64";
+ return "Dbgeng x64 (64-bit module)";
}
@Override
public int getConfidence() {
- return 100;
+ return HostDebuggerPlatformOpinion.CONFIDENCE_HOST_KNOWN + 10;
}
@Override
@@ -72,7 +191,60 @@ public class DbgengDebuggerPlatformOpinion extends AbstractDebuggerPlatformOpini
public boolean isCreatorOf(DebuggerPlatformMapper mapper) {
return mapper.getClass() == DbgengX64DebuggerPlatformMapper.class;
}
- };
+ },
+ X64_32 {
+ @Override
+ public String getDescription() {
+ return "Dbgeng x64 (32-bit module)";
+ }
+
+ @Override
+ public int getConfidence() {
+ return HostDebuggerPlatformOpinion.CONFIDENCE_HOST_KNOWN + 10;
+ }
+
+ @Override
+ public CompilerSpec getCompilerSpec() {
+ return getCompilerSpec(LANG_ID_X86_64_32, COMP_ID_VS);
+ }
+
+ @Override
+ public DebuggerPlatformMapper take(PluginTool tool, Trace trace) {
+ return new DbgengX64_32DebuggerPlatformMapper(tool, trace, getCompilerSpec());
+ }
+
+ @Override
+ public boolean isCreatorOf(DebuggerPlatformMapper mapper) {
+ return mapper.getClass() == DbgengX64_32DebuggerPlatformMapper.class;
+ }
+ },
+ WOW64 {
+ @Override
+ public String getDescription() {
+ return "Dbgeng x64 (WoW64)";
+ }
+
+ @Override
+ public int getConfidence() {
+ return HostDebuggerPlatformOpinion.CONFIDENCE_HOST_KNOWN + 20;
+ }
+
+ @Override
+ public CompilerSpec getCompilerSpec() {
+ // Report x86-32 in opinions, even though we mix
+ return getCompilerSpec(LANG_ID_X86_64_32, COMP_ID_VS);
+ }
+
+ @Override
+ public DebuggerPlatformMapper take(PluginTool tool, Trace trace) {
+ return new DbgengWoW64DebuggerPlatformMapper(tool, trace, getCompilerSpec());
+ }
+
+ @Override
+ public boolean isCreatorOf(DebuggerPlatformMapper mapper) {
+ return mapper.getClass() == DbgengWoW64DebuggerPlatformMapper.class;
+ }
+ },;
}
@Override
@@ -85,6 +257,6 @@ public class DbgengDebuggerPlatformOpinion extends AbstractDebuggerPlatformOpini
if (!is64Bit) {
return Set.of();
}
- return Set.of(Offers.X64);
+ return Set.of(Offer.X64, Offer.X64_32, Offer.WOW64);
}
}
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 2c25fe9dad..ee25112275 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
@@ -15,32 +15,19 @@
*/
package ghidra.app.plugin.core.debug.platform.dbgeng;
-import java.io.IOException;
import java.math.BigInteger;
-import java.util.Collection;
-import java.util.Set;
-import java.util.stream.Collectors;
import ghidra.app.plugin.core.debug.disassemble.*;
import ghidra.app.plugin.core.debug.disassemble.DisassemblyInjectInfo.PlatformInfo;
-import ghidra.app.services.DebuggerTargetService;
-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.debug.api.target.Target;
+import ghidra.app.plugin.core.debug.platform.dbgeng.DbgengDebuggerPlatformOpinion.Mode;
import ghidra.framework.plugintool.PluginTool;
-import ghidra.program.model.address.*;
+import ghidra.program.model.address.AddressRange;
+import ghidra.program.model.address.AddressSetView;
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.guest.TracePlatform;
-import ghidra.trace.model.modules.TraceModule;
import ghidra.trace.model.thread.TraceThread;
-import ghidra.util.Msg;
-import ghidra.util.exception.CancelledException;
-import ghidra.util.task.TaskMonitor;
@DisassemblyInjectInfo(
platforms = {
@@ -48,11 +35,6 @@ import ghidra.util.task.TaskMonitor;
@PlatformInfo(langID = "x86:LE:64:default", compilerID = "clangwindows"),
})
public class DbgengX64DisassemblyInject implements DisassemblyInject {
-
- enum Mode {
- X64, X86, UNK;
- }
-
@Override
public void pre(PluginTool tool, TraceDisassembleCommand command, TracePlatform platform,
long snap, TraceThread thread, AddressSetView startSet, AddressSetView restricted) {
@@ -61,21 +43,11 @@ public class DbgengX64DisassemblyInject implements DisassemblyInject {
return;
}
Trace trace = platform.getTrace();
- DebuggerTargetService targetService = tool.getService(DebuggerTargetService.class);
- Target target = targetService == null ? null : targetService.getTarget(trace);
- Collection extends TraceModule> modules =
- trace.getModuleManager().getModulesAt(snap, first.getMinAddress());
- Msg.debug(this, "Disassembling in modules: " +
- modules.stream().map(m -> m.getName(snap)).collect(Collectors.joining(",")));
- Set modes = modules.stream()
- .map(m -> modeForModule(target, trace, snap, m))
- .filter(m -> m != Mode.UNK)
- .collect(Collectors.toSet());
- Msg.debug(this, "Disassembling in mode(s): " + modes);
- if (modes.size() != 1) {
+
+ Mode mode = Mode.computeFor(tool, trace, first.getMinAddress(), snap);
+ if (mode == Mode.UNK) {
return;
}
- Mode mode = modes.iterator().next();
Language language = platform.getLanguage();
Register longModeReg = language.getRegister("longMode");
@@ -96,36 +68,4 @@ public class DbgengX64DisassemblyInject implements DisassemblyInject {
default -> throw new AssertionError();
});
}
-
- protected Mode modeForModule(Target target, Trace trace, long snap,
- TraceModule module) {
- if (target != null && target.getSnap() == snap) {
- AddressSet set = new AddressSet();
- set.add(module.getBase(snap), module.getBase(snap)); // Recorder should read page
- try {
- target.readMemory(set, TaskMonitor.DUMMY);
- trace.flushEvents();
- }
- catch (CancelledException e) {
- throw new AssertionError(e);
- }
- }
- MemBuffer bufferAt = trace.getMemoryManager().getBufferAt(snap, module.getBase(snap));
- try (ByteProvider bp = new MemBufferByteProvider(bufferAt)) {
- PortableExecutable pe = new PortableExecutable(bp, SectionLayout.MEMORY, false, false);
- NTHeader ntHeader = pe.getNTHeader();
- if (ntHeader == null) {
- return Mode.UNK;
- }
- OptionalHeader optionalHeader = ntHeader.getOptionalHeader();
- if (optionalHeader == null) {
- return Mode.UNK; // Really shouldn't happen, but who knows?
- }
- return optionalHeader.is64bit() ? Mode.X64 : Mode.X86;
- }
- catch (IOException e) {
- Msg.warn(this, "Could not parse PE from trace: " + e);
- return Mode.UNK;
- }
- }
}
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
index b5c7461d3c..b3ab9d2eba 100644
--- 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
@@ -4,9 +4,9 @@
* 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.
@@ -21,7 +21,8 @@ import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
import ghidra.app.plugin.core.debug.event.DebuggerPlatformPluginEvent;
import ghidra.app.plugin.core.debug.event.TraceClosedPluginEvent;
-import ghidra.app.plugin.core.debug.mapping.*;
+import ghidra.app.plugin.core.debug.mapping.DebuggerPlatformOffer;
+import ghidra.app.plugin.core.debug.mapping.DebuggerPlatformOpinion;
import ghidra.app.services.DebuggerPlatformService;
import ghidra.app.services.DebuggerTraceManagerService;
import ghidra.debug.api.platform.DebuggerPlatformMapper;
@@ -29,6 +30,7 @@ import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.annotation.AutoServiceConsumed;
import ghidra.framework.plugintool.util.PluginStatus;
import ghidra.trace.model.Trace;
+import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.target.TraceObject;
@PluginInfo(
@@ -85,7 +87,6 @@ public class DebuggerPlatformServicePlugin extends Plugin implements DebuggerPla
}
mappersByTrace.put(trace, mapper);
}
- mapper.addToTrace(snap);
firePluginEvent(new DebuggerPlatformPluginEvent(getName(), trace, mapper));
return mapper;
}
@@ -103,7 +104,7 @@ public class DebuggerPlatformServicePlugin extends Plugin implements DebuggerPla
}
@Override
- public void setCurrentMapperFor(Trace trace, DebuggerPlatformMapper mapper, long snap) {
+ public void setCurrentMapperFor(Trace trace, TraceObject focus, DebuggerPlatformMapper mapper, long snap) {
Objects.requireNonNull(trace);
Objects.requireNonNull(mapper);
if (!traceManager.getOpenTraces().contains(trace)) {
@@ -112,8 +113,11 @@ public class DebuggerPlatformServicePlugin extends Plugin implements DebuggerPla
synchronized (mappersByTrace) {
mappersByTrace.put(trace, mapper);
}
- mapper.addToTrace(snap);
+ TracePlatform platform = mapper.addToTrace(focus, snap);
firePluginEvent(new DebuggerPlatformPluginEvent(getName(), trace, mapper));
+ if (traceManager.getCurrentTrace() == trace) {
+ traceManager.activatePlatform(platform);
+ }
}
@Override
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/tracemgr/DebuggerTraceManagerServicePlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/tracemgr/DebuggerTraceManagerServicePlugin.java
index 74ba2f6b70..364528bb86 100644
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/tracemgr/DebuggerTraceManagerServicePlugin.java
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/tracemgr/DebuggerTraceManagerServicePlugin.java
@@ -535,8 +535,7 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
if (mapper == null) {
return coordinates;
}
- TracePlatform platform =
- getPlatformForMapper(coordinates.getTrace(), coordinates.getObject(), mapper);
+ TracePlatform platform = mapper.addToTrace(coordinates.getObject(), coordinates.getSnap());
return coordinates.platform(platform);
}
@@ -598,22 +597,22 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
return mode.followsPresent();
}
- protected TracePlatform getPlatformForMapper(Trace trace, TraceObject object,
- DebuggerPlatformMapper mapper) {
- return trace.getPlatformManager().getPlatform(mapper.getCompilerSpec(object));
- }
-
protected void doPlatformMapperSelected(Trace trace, DebuggerPlatformMapper mapper) {
synchronized (listenersByTrace) {
if (!listenersByTrace.containsKey(trace)) {
return;
}
LastCoords cur = lastCoordsByTrace.getOrDefault(trace, LastCoords.NEVER);
- DebuggerCoordinates adj =
- cur.coords.platform(getPlatformForMapper(trace, cur.coords.getObject(), mapper));
+ TracePlatform platform =
+ mapper.addToTrace(cur.coords.getObject(), cur.coords.getSnap());
+ if (cur.coords.getPlatform() == platform) {
+ return;
+ }
+ DebuggerCoordinates adj = cur.coords.platform(platform);
lastCoordsByTrace.put(trace, cur.keepTime(adj));
if (trace == current.getTrace()) {
current = adj;
+ trace.getProgramView().setPlatform(adj.getPlatform());
fireLocationEvent(adj, ActivationCause.MAPPER_CHANGED);
}
}
@@ -789,6 +788,7 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
return; // We navigated elsewhere before emulation completed
}
varView.setSnap(snap);
+ varView.setPlatform(coordinates.getPlatform());
fireLocationEvent(coordinates, cause);
}, cause == ActivationCause.EMU_STATE_EDIT
? SwingExecutorService.MAYBE_NOW // ProgramView may call .get on Swing thread
@@ -1167,7 +1167,9 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
if (current.getTrace() != newTrace) {
// The snap needs to match upon re-activating this trace.
try {
- newTrace.getProgramView().setSnap(coordinates.getViewSnap());
+ TraceVariableSnapProgramView view = newTrace.getProgramView();
+ view.setSnap(coordinates.getViewSnap());
+ view.setPlatform(coordinates.getPlatform());
}
catch (TraceClosedException e) {
// Presumably, a closed event is queued
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/stack/AnalysisUnwoundFrame.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/stack/AnalysisUnwoundFrame.java
index 35d23cb877..8e931d3ea3 100644
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/stack/AnalysisUnwoundFrame.java
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/stack/AnalysisUnwoundFrame.java
@@ -4,9 +4,9 @@
* 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.
@@ -22,8 +22,8 @@ import java.util.stream.Collectors;
import ghidra.app.plugin.core.bookmark.BookmarkNavigator;
import ghidra.app.services.DebuggerControlService.StateEditor;
-import ghidra.debug.api.tracemgr.DebuggerCoordinates;
import ghidra.app.services.DebuggerStaticMappingService;
+import ghidra.debug.api.tracemgr.DebuggerCoordinates;
import ghidra.framework.plugintool.PluginTool;
import ghidra.pcode.exec.BytesPcodeArithmetic;
import ghidra.pcode.exec.PcodeExecutorState;
@@ -352,7 +352,7 @@ public class AnalysisUnwoundFrame extends AbstractUnwoundFrame {
spPlusParams.add(structure.getLength() - 1)), false, monitor);
TraceData frame = trace.getCodeManager()
.definedData()
- .create(span, spPlusParams, structure);
+ .create(span, spPlusParams, platform, structure);
frame.setComment(CodeUnit.PRE_COMMENT, getDescription());
TraceReferenceManager refs = trace.getReferenceManager();
refs.clearReferencesFrom(span, frame.getRange());
diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/platform/DebuggerPlatformPluginTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/platform/DebuggerPlatformPluginTest.java
index d7c6609c08..8a7a490c3f 100644
--- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/platform/DebuggerPlatformPluginTest.java
+++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/platform/DebuggerPlatformPluginTest.java
@@ -4,9 +4,9 @@
* 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.
@@ -29,6 +29,7 @@ import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerTest;
import ghidra.app.plugin.core.debug.mapping.DebuggerPlatformOffer;
import ghidra.app.services.DebuggerPlatformService;
import ghidra.debug.api.platform.DebuggerPlatformMapper;
+import ghidra.debug.api.tracemgr.DebuggerCoordinates;
import ghidra.program.model.lang.LanguageID;
import ghidra.trace.database.ToyDBTraceBuilder;
@@ -73,10 +74,12 @@ public class DebuggerPlatformPluginTest extends AbstractGhidraHeadedDebuggerTest
public void testActionMore() throws Throwable {
createAndOpenTrace("DATA:BE:64:default");
traceManager.activateTrace(tb.trace);
-
+
chooseLanguageIDViaMore(new LanguageID("Toy:BE:64:default"));
DebuggerPlatformMapper mapper = platformService.getCurrentMapperFor(tb.trace);
- assertEquals(new LanguageID("Toy:BE:64:default"), mapper.getLangauge(null).getLanguageID());
+ DebuggerCoordinates current = traceManager.getCurrent();
+ assertEquals(new LanguageID("Toy:BE:64:default"),
+ mapper.getLangauge(current.getObject(), current.getSnap()).getLanguageID());
}
@Test
diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/emulation/DebuggerEmulationServiceTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/emulation/DebuggerEmulationServiceTest.java
index 77f796e33e..5ec079b998 100644
--- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/emulation/DebuggerEmulationServiceTest.java
+++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/emulation/DebuggerEmulationServiceTest.java
@@ -334,7 +334,7 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerTe
.findAny()
.orElse(null)
.take(tool, tb.trace);
- platformPlugin.setCurrentMapperFor(tb.trace, mapper, 0);
+ platformPlugin.setCurrentMapperFor(tb.trace, null, mapper, 0);
waitForSwing();
waitForPass(() -> assertEquals(x64, traceManager.getCurrentPlatform().getLanguage()));
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 09da21e3c8..69240ad4ea 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
@@ -4,9 +4,9 @@
* 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.
@@ -335,10 +335,11 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
}
@DependentService
- protected DBTraceDataTypeManager createDataTypeManager()
+ protected DBTraceDataTypeManager createDataTypeManager(DBTracePlatformManager platformManager)
throws CancelledException, IOException {
return createTraceManager("Data Type Manager", (openMode,
- monitor) -> new DBTraceDataTypeManager(dbh, openMode, rwLock, monitor, this));
+ monitor) -> new DBTraceDataTypeManager(dbh, openMode, rwLock, monitor, this,
+ platformManager.getHostPlatform()));
}
@DependentService
@@ -352,7 +353,7 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
@DependentService
protected DBTracePlatformManager createPlatformManager()
throws CancelledException, IOException {
- return createTraceManager("Language Manager",
+ return createTraceManager("Platform Manager",
(openMode, monitor) -> new DBTracePlatformManager(dbh, openMode, rwLock, monitor,
baseCompilerSpec, this));
}
@@ -514,7 +515,7 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
}
@Override
- public DBTraceDataTypeManager getDataTypeManager() {
+ public DBTraceDataTypeManager getBaseDataTypeManager() {
return dataTypeManager;
}
@@ -761,8 +762,6 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
}
}
- // TODO: Platform option?
-
public void setExecutablePath(String path) {
getOptions(TRACE_INFO).setString(EXECUTABLE_PATH, path);
}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/data/DBTraceDataTypeManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/data/DBTraceDataTypeManager.java
index 832d6e0e50..c54a3ce63e 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/data/DBTraceDataTypeManager.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/data/DBTraceDataTypeManager.java
@@ -4,9 +4,9 @@
* 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.
@@ -26,11 +26,12 @@ import ghidra.framework.data.OpenMode;
import ghidra.framework.model.DomainFile;
import ghidra.program.database.data.ProgramBasedDataTypeManagerDB;
import ghidra.program.model.address.Address;
-import ghidra.program.model.address.AddressFactory;
import ghidra.program.model.data.*;
-import ghidra.program.model.lang.*;
import ghidra.trace.database.DBTrace;
import ghidra.trace.database.DBTraceManager;
+import ghidra.trace.database.guest.DBTraceGuestPlatform;
+import ghidra.trace.database.guest.DBTracePlatformManager.DBTraceHostPlatform;
+import ghidra.trace.database.guest.InternalTracePlatform;
import ghidra.trace.model.data.TraceBasedDataTypeManager;
import ghidra.util.InvalidNameException;
import ghidra.util.UniversalID;
@@ -41,35 +42,37 @@ import ghidra.util.task.TaskMonitor;
public class DBTraceDataTypeManager extends ProgramBasedDataTypeManagerDB
implements TraceBasedDataTypeManager, DBTraceManager {
- protected final ReadWriteLock lock; // TODO: This lock object is not used
+ /**
+ * NOTE: This "read-write" lock is actually just a compatibility wrapper around the
+ * {@link ghidra.util.Lock} for the entire trace database. There was a time when I dreamed of
+ * using an actual read-write lock (though it's not known if that'd actually achieve any
+ * appreciable speed up); however, inheriting the existing DataTypeManager implementation
+ * required its lock to be used throughout the database. Rather than convert all my code (and
+ * lose the distinction of where I need write vs. read locks), I just wrapped the API. So no,
+ * this code does not refer to the wrapper, but it does still use the lock. I keep a reference
+ * to it here in case I ever need it.
+ */
+ protected final ReadWriteLock lock;
protected final DBTrace trace;
+ protected final InternalTracePlatform platform;
- private static final String INSTANCE_TABLE_PREFIX = null; // placeholder only
+ private static String computePrefix(InternalTracePlatform platform) {
+ return switch (platform) {
+ case DBTraceHostPlatform host -> null;
+ case DBTraceGuestPlatform guest -> "Guest%d_".formatted(guest.getIntKey());
+ default -> throw new AssertionError();
+ };
+ }
public DBTraceDataTypeManager(DBHandle dbh, OpenMode openMode, ReadWriteLock lock,
- TaskMonitor monitor, DBTrace trace)
+ TaskMonitor monitor, DBTrace trace, InternalTracePlatform platform)
throws CancelledException, VersionException, IOException {
- super(dbh, null, openMode, INSTANCE_TABLE_PREFIX, trace, trace.getLock(), monitor);
+ super(dbh, null, openMode, computePrefix(platform), trace, trace.getLock(), monitor);
this.lock = lock; // TODO: nothing uses this local lock - not sure what its purpose is
this.trace = trace;
+ this.platform = platform;
- setProgramArchitecture(new ProgramArchitecture() {
-
- @Override
- public Language getLanguage() {
- return trace.getBaseLanguage();
- }
-
- @Override
- public CompilerSpec getCompilerSpec() {
- return trace.getBaseCompilerSpec();
- }
-
- @Override
- public AddressFactory getAddressFactory() {
- return trace.getBaseAddressFactory();
- }
- }, null, false, monitor);
+ setProgramArchitecture(platform, null, false, monitor);
if (openMode == OpenMode.CREATE) {
saveDataOrganization();
@@ -106,6 +109,11 @@ public class DBTraceDataTypeManager extends ProgramBasedDataTypeManagerDB
categoryRenamed(CategoryPath.ROOT, getCategory(CategoryPath.ROOT));
}
+ @Override
+ public InternalTracePlatform getPlatform() {
+ return platform;
+ }
+
@Override
public void sourceArchiveChanged(UniversalID sourceArchiveID) {
super.sourceArchiveChanged(sourceArchiveID);
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTraceGuestPlatform.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTraceGuestPlatform.java
index 91903664c9..6336111657 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTraceGuestPlatform.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTraceGuestPlatform.java
@@ -22,7 +22,9 @@ import java.util.Map.Entry;
import org.apache.commons.lang3.tuple.Pair;
import db.DBRecord;
+import generic.jar.ResourceFile;
import ghidra.app.util.PseudoInstruction;
+import ghidra.framework.data.OpenMode;
import ghidra.lifecycle.Internal;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.*;
@@ -32,8 +34,10 @@ 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.database.data.DBTraceDataTypeManager;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.Trace;
+import ghidra.trace.model.data.TraceBasedDataTypeManager;
import ghidra.trace.model.guest.TraceGuestPlatform;
import ghidra.trace.model.guest.TraceGuestPlatformMappedRange;
import ghidra.trace.util.*;
@@ -156,6 +160,8 @@ public class DBTraceGuestPlatform extends DBAnnotatedObject
new TreeMap<>();
protected final AddressSet guestAddressSet = new AddressSet();
+ protected DBTraceDataTypeManager dataTypeManager;
+
public DBTraceGuestPlatform(DBTracePlatformManager manager, DBCachedObjectStore> store,
DBRecord record) {
super(store, record);
@@ -187,6 +193,12 @@ public class DBTraceGuestPlatform extends DBAnnotatedObject
}
}
+ protected void loadDataTypeManager(OpenMode openMode, TaskMonitor monitor)
+ throws CancelledException, VersionException, IOException {
+ this.dataTypeManager = new DBTraceDataTypeManager(manager.dbh, openMode, manager.lock,
+ monitor, manager.trace, this);
+ }
+
@Override
public Trace getTrace() {
return manager.trace;
@@ -235,6 +247,11 @@ public class DBTraceGuestPlatform extends DBAnnotatedObject
return compilerSpec;
}
+ @Override
+ public TraceBasedDataTypeManager getDataTypeManager() {
+ return dataTypeManager;
+ }
+
@Override
public void delete(TaskMonitor monitor) throws CancelledException {
manager.deleteGuestPlatform(this, monitor);
@@ -284,6 +301,12 @@ public class DBTraceGuestPlatform extends DBAnnotatedObject
return next.getMaxAddress().add(1);
}
+ private static ResourceFile getSlaFile(Language language) {
+ SleighLanguageDescription desc =
+ (SleighLanguageDescription) language.getLanguageDescription();
+ return desc.getSlaFile();
+ }
+
@Override
public TraceGuestPlatformMappedRange addMappedRegisterRange()
throws AddressOverflowException {
@@ -292,8 +315,24 @@ public class DBTraceGuestPlatform extends DBAnnotatedObject
if (guestRange == null) {
return null; // No registers, so we're mapped!
}
- Address hostMin = manager.computeNextRegisterMin();
long size = guestRange.getLength();
+
+ /**
+ * If the two languages are really the same (have the same .sla file), then map
+ * registers identically. Such languages differ only in their default contextreg values.
+ */
+ ResourceFile hostSla = getSlaFile(manager.hostPlatform.getLanguage());
+ ResourceFile guestSla = getSlaFile(getLanguage());
+ Address hostMin;
+ if (Objects.equals(hostSla, guestSla)) {
+ hostMin = manager.hostPlatform.getAddressFactory()
+ .getRegisterSpace()
+ .getAddress(guestRange.getMinAddress().getOffset());
+ }
+ else {
+ hostMin = manager.computeNextRegisterMin();
+ }
+
return addMappedRange(hostMin, guestRange.getMinAddress(), size);
}
}
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
index 2d9a34826f..15afbf3003 100644
--- 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
@@ -29,6 +29,7 @@ import ghidra.trace.database.DBTrace;
import ghidra.trace.database.DBTraceManager;
import ghidra.trace.database.guest.DBTraceGuestPlatform.DBTraceGuestLanguage;
import ghidra.trace.model.Trace;
+import ghidra.trace.model.data.TraceBasedDataTypeManager;
import ghidra.trace.model.guest.*;
import ghidra.trace.util.TraceChangeRecord;
import ghidra.trace.util.TraceEvents;
@@ -61,7 +62,8 @@ public class DBTracePlatformManager implements DBTraceManager, TracePlatformMana
protected final DBCachedObjectStore rangeMappingStore;
- protected final InternalTracePlatform hostPlatform = new InternalTracePlatform() {
+ @Internal
+ public class DBTraceHostPlatform implements InternalTracePlatform {
@Override
public Trace getTrace() {
return trace;
@@ -97,6 +99,11 @@ public class DBTracePlatformManager implements DBTraceManager, TracePlatformMana
return trace.getBaseAddressFactory();
}
+ @Override
+ public TraceBasedDataTypeManager getDataTypeManager() {
+ return trace.getBaseDataTypeManager();
+ }
+
@Override
public AddressSetView getHostAddressSet() {
return trace.getBaseAddressFactory().getAddressSet();
@@ -146,11 +153,13 @@ public class DBTracePlatformManager implements DBTraceManager, TracePlatformMana
public InstructionSet mapGuestInstructionAddressesToHost(InstructionSet set) {
return set;
}
- };
+ }
+
+ protected final InternalTracePlatform hostPlatform = new DBTraceHostPlatform();
public DBTracePlatformManager(DBHandle dbh, OpenMode openMode, ReadWriteLock lock,
TaskMonitor monitor, CompilerSpec baseCompilerSpec, DBTrace trace)
- throws VersionException, IOException {
+ throws VersionException, IOException, CancelledException {
this.dbh = dbh;
this.lock = lock;
this.baseLanguage = baseCompilerSpec.getLanguage();
@@ -169,7 +178,7 @@ public class DBTracePlatformManager implements DBTraceManager, TracePlatformMana
(s, r) -> new DBTraceGuestPlatformMappedRange(this, s, r), true);
loadLanguages();
- loadPlatforms();
+ loadPlatforms(openMode, monitor);
loadPlatformMappings();
}
@@ -179,9 +188,10 @@ public class DBTracePlatformManager implements DBTraceManager, TracePlatformMana
}
}
- protected void loadPlatforms()
- throws LanguageNotFoundException, CompilerSpecNotFoundException, VersionException {
+ protected void loadPlatforms(OpenMode openMode, TaskMonitor monitor)
+ throws VersionException, CancelledException, IOException {
for (DBTraceGuestPlatform platformEntry : platformStore.asMap().values()) {
+ platformEntry.loadDataTypeManager(openMode, monitor);
platformsByCompiler.put(platformEntry.getCompilerSpec(), platformEntry);
}
}
@@ -263,10 +273,11 @@ public class DBTracePlatformManager implements DBTraceManager, TracePlatformMana
platformsByCompiler.clear();
try {
loadLanguages();
- loadPlatforms();
+ // TODO: Or IMMUTABLE, if that was the original, and supported
+ loadPlatforms(OpenMode.UPDATE, TaskMonitor.DUMMY);
loadPlatformMappings();
}
- catch (LanguageNotFoundException | CompilerSpecNotFoundException | VersionException e) {
+ catch (IOException | VersionException | CancelledException e) {
throw new AssertionError(e);
}
}
@@ -300,6 +311,12 @@ public class DBTracePlatformManager implements DBTraceManager, TracePlatformMana
protected DBTraceGuestPlatform doAddGuestPlatform(CompilerSpec compilerSpec) {
DBTraceGuestPlatform platformEntry = platformStore.create();
platformEntry.set(compilerSpec);
+ try {
+ platformEntry.loadDataTypeManager(OpenMode.CREATE, TaskMonitor.DUMMY);
+ }
+ catch (CancelledException | VersionException | IOException e) {
+ throw new AssertionError(e);
+ }
platformsByCompiler.put(compilerSpec, platformEntry);
return platformEntry;
}
@@ -330,12 +347,11 @@ public class DBTracePlatformManager implements DBTraceManager, TracePlatformMana
@Override
public InternalTracePlatform getOrAddPlatform(CompilerSpec compilerSpec) {
- if (compilerSpec.getCompilerSpecID()
- .equals(trace.getBaseCompilerSpec().getCompilerSpecID())) {
- return hostPlatform;
- }
DBTraceGuestPlatform platform;
try (LockHold hold = LockHold.lock(lock.writeLock())) {
+ if (trace.getBaseCompilerSpec() == compilerSpec) {
+ return hostPlatform;
+ }
DBTraceGuestPlatform exists = platformsByCompiler.get(compilerSpec);
if (exists != null) {
return exists;
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/InternalTracePlatform.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/InternalTracePlatform.java
index 220acddcac..0004099c6e 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/InternalTracePlatform.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/InternalTracePlatform.java
@@ -18,8 +18,7 @@ package ghidra.trace.database.guest;
import java.util.*;
import ghidra.program.model.address.*;
-import ghidra.program.model.lang.Language;
-import ghidra.program.model.lang.Register;
+import ghidra.program.model.lang.*;
import ghidra.program.model.symbol.SourceType;
import ghidra.trace.database.guest.DBTraceGuestPlatform.DBTraceGuestLanguage;
import ghidra.trace.model.guest.TracePlatform;
@@ -34,7 +33,7 @@ import ghidra.util.LockHold;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.InvalidInputException;
-public interface InternalTracePlatform extends TracePlatform {
+public interface InternalTracePlatform extends TracePlatform, ProgramArchitecture {
String REG_MAP_BE = "__reg_map_be__";
String REG_MAP_LE = "__reg_map_le__";
@@ -51,6 +50,11 @@ public interface InternalTracePlatform extends TracePlatform {
DBTraceGuestLanguage getLanguageEntry();
+ @Override
+ default AddressFactory getAddressFactory() {
+ return TracePlatform.super.getAddressFactory();
+ }
+
@Override
default AddressRange getConventionalRegisterRange(AddressSpace space, Register register) {
AddressRange result = mapGuestToHost(TraceRegisterUtils.rangeForRegister(register));
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 4055d999fb..f0966db6ff 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
@@ -4,9 +4,9 @@
* 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.
@@ -28,8 +28,8 @@ import ghidra.program.model.lang.Language;
import ghidra.program.model.mem.*;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.trace.database.DBTrace;
-import ghidra.trace.database.data.DBTraceDataTypeManager;
import ghidra.trace.database.guest.DBTraceGuestPlatform;
+import ghidra.trace.database.guest.DBTracePlatformManager;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapSpace;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager.DBTraceSpaceEntry;
@@ -63,7 +63,7 @@ public class DBTraceCodeSpace implements TraceCodeSpace, DBTraceSpaceBased {
protected final ReadWriteLock lock;
protected final Language baseLanguage;
protected final DBTrace trace;
- protected final DBTraceDataTypeManager dataTypeManager;
+ protected final DBTracePlatformManager platformManager;
protected final DBTraceReferenceManager referenceManager;
protected final AddressRange all;
@@ -99,7 +99,7 @@ public class DBTraceCodeSpace implements TraceCodeSpace, DBTraceSpaceBased {
this.lock = manager.getLock();
this.baseLanguage = manager.getBaseLanguage();
this.trace = manager.getTrace();
- this.dataTypeManager = manager.dataTypeManager;
+ this.platformManager = manager.platformManager;
this.referenceManager = manager.referenceManager;
this.all = new AddressRangeImpl(space.getMinAddress(), space.getMaxAddress());
@@ -335,7 +335,7 @@ public class DBTraceCodeSpace implements TraceCodeSpace, DBTraceSpaceBased {
if (reApply) {
try {
definedData.create(Lifespan.span(unitStartSnap, unitEndSnap),
- unit.getAddress(), dataType, unit.getLength());
+ unit.getAddress(), unit.getPlatform(), dataType, unit.getLength());
}
catch (CodeUnitInsertionException e) {
throw new AssertionError(e);
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 75a7b5cd67..40bdce0a0e 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
@@ -4,9 +4,9 @@
* 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.
@@ -92,7 +92,7 @@ public class DBTraceData extends AbstractDBTraceCodeUnit
if (platform == null) {
throw new IOException("Data table is corrupt. Missing platform: " + platformKey);
}
- dataType = space.dataTypeManager.getDataType(dataTypeID);
+ dataType = platform.getDataTypeManager().getDataType(dataTypeID);
if (dataType == null) {
throw new IOException("Data table is corrupt. Missing datatype: " + dataTypeID);
}
@@ -128,7 +128,7 @@ public class DBTraceData extends AbstractDBTraceCodeUnit
this.platform = platform;
// Use the stored dataType, not the given one, in case it's different
- this.dataType = space.dataTypeManager.getDataType(dataTypeID);
+ this.dataType = platform.getDataTypeManager().getDataType(dataTypeID);
assert this.dataType != null;
this.defaultSettings = this.dataType.getDefaultSettings();
this.baseDataType = getBaseDataType(this.dataType);
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceDefinedDataMemoryView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceDefinedDataMemoryView.java
index 270cf8c341..73e7ec5c16 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceDefinedDataMemoryView.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceDefinedDataMemoryView.java
@@ -4,9 +4,9 @@
* 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.
@@ -20,6 +20,7 @@ import ghidra.program.model.address.AddressRange;
import ghidra.program.model.data.DataType;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.trace.model.Lifespan;
+import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.listing.TraceCodeManager;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
@@ -52,15 +53,16 @@ public class DBTraceDefinedDataMemoryView
}
@Override
- public DBTraceDataAdapter create(Lifespan lifespan, Address address, DataType dataType,
- int length) throws CodeUnitInsertionException {
+ public DBTraceDataAdapter create(Lifespan lifespan, Address address, TracePlatform platform,
+ DataType dataType, int length) throws CodeUnitInsertionException {
return delegateWrite(address.getAddressSpace(),
- m -> m.create(lifespan, address, dataType, length));
+ m -> m.create(lifespan, address, platform, dataType, length));
}
@Override
- public DBTraceDataAdapter create(Lifespan lifespan, Address address, DataType dataType)
- throws CodeUnitInsertionException {
- return delegateWrite(address.getAddressSpace(), m -> m.create(lifespan, address, dataType));
+ public DBTraceDataAdapter create(Lifespan lifespan, Address address, TracePlatform platform,
+ DataType dataType) throws CodeUnitInsertionException {
+ return delegateWrite(address.getAddressSpace(),
+ m -> m.create(lifespan, address, platform, dataType));
}
}
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 342216676d..c24a208004 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
@@ -4,9 +4,9 @@
* 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.
@@ -19,8 +19,10 @@ import ghidra.program.model.address.*;
import ghidra.program.model.data.*;
import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.util.CodeUnitInsertionException;
+import ghidra.trace.database.guest.InternalTracePlatform;
import ghidra.trace.database.memory.DBTraceMemorySpace;
import ghidra.trace.model.*;
+import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.listing.TraceCodeSpace;
import ghidra.trace.util.TraceChangeRecord;
import ghidra.trace.util.TraceEvents;
@@ -41,9 +43,9 @@ public class DBTraceDefinedDataView extends AbstractBaseDBTraceDefinedUnitsView<
}
@Override // NOTE: "Adapter" because using DataType.DEFAULT gives UndefinedDBTraceData
- public DBTraceDataAdapter create(Lifespan lifespan, Address address, DataType dataType)
- throws CodeUnitInsertionException {
- return create(lifespan, address, dataType, dataType.getLength());
+ public DBTraceDataAdapter create(Lifespan lifespan, Address address, TracePlatform platform,
+ DataType dataType) throws CodeUnitInsertionException {
+ return create(lifespan, address, platform, dataType, dataType.getLength());
}
/**
@@ -67,9 +69,12 @@ public class DBTraceDefinedDataView extends AbstractBaseDBTraceDefinedUnitsView<
}
@Override
- // TODO: Probably add language parameter....
- public DBTraceDataAdapter create(Lifespan lifespan, Address address, DataType origType,
- int origLength) throws CodeUnitInsertionException {
+ public DBTraceDataAdapter create(Lifespan lifespan, Address address, TracePlatform platform,
+ DataType origType, int origLength) throws CodeUnitInsertionException {
+ if (platform.getTrace() != getTrace() ||
+ !(platform instanceof InternalTracePlatform iPlatform)) {
+ throw new IllegalArgumentException("Platform is not part of this trace");
+ }
try (LockHold hold = LockHold.lock(space.lock.writeLock())) {
DBTraceMemorySpace memSpace = space.trace.getMemoryManager().get(space, true);
// NOTE: User-given length could be ignored....
@@ -97,12 +102,11 @@ public class DBTraceDefinedDataView extends AbstractBaseDBTraceDefinedUnitsView<
if (dataType == null) {
throw new CodeUnitInsertionException("Failed to resolve data type");
}
- // TODO: This clone may need to be sensitive to the unit's language.
- dataType = dataType.clone(space.dataTypeManager);
+ DataTypeManager dtm = platform.getDataTypeManager();
+ dataType = dataType.clone(dtm);
if (isFunctionDefinition(dataType)) {
- // TODO: This pointer will need to be sensitive to the unit's language.
- dataType = new PointerDataType(dataType, dataType.getDataTypeManager());
+ dataType = new PointerDataType(dataType, dtm);
length = dataType.getLength();
}
else if (dataType instanceof Dynamic) {
@@ -112,8 +116,6 @@ public class DBTraceDefinedDataView extends AbstractBaseDBTraceDefinedUnitsView<
MemBuffer buffer = memSpace.getBufferAt(startSnap, address);
length = dyn.getLength(buffer, length);
}
- // TODO: Do I need to check for Pointer type here?
- // Seems purpose is to adjust for language, but I think clone does that already
else {
length = dataType.getLength();
}
@@ -143,10 +145,9 @@ public class DBTraceDefinedDataView extends AbstractBaseDBTraceDefinedUnitsView<
return space.undefinedData.getAt(startSnap, address);
}
- long dataTypeID = space.dataTypeManager.getResolvedID(dataType);
+ long dataTypeID = dtm.getResolvedID(dataType);
DBTraceData created = mapSpace.put(tasr, null);
- // TODO: data units with a guest platform
- created.set(space.trace.getPlatformManager().getHostPlatform(), dataTypeID);
+ created.set(iPlatform, dataTypeID);
// TODO: Explicitly remove undefined from cache, or let weak refs take care of it?
cacheForContaining.notifyNewEntry(tasr.getLifespan(), createdRange, created);
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/InternalTraceDefinedDataView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/InternalTraceDefinedDataView.java
index 08770062f7..9eb99f7361 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/InternalTraceDefinedDataView.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/InternalTraceDefinedDataView.java
@@ -4,9 +4,9 @@
* 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.
@@ -15,24 +15,60 @@
*/
package ghidra.trace.database.listing;
+import ghidra.lifecycle.Internal;
+import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressRange;
import ghidra.program.model.data.DataType;
import ghidra.program.model.lang.Register;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.trace.model.Lifespan;
+import ghidra.trace.model.data.TraceBasedDataTypeManager;
import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.listing.TraceData;
import ghidra.trace.model.listing.TraceDefinedDataView;
import ghidra.trace.util.TraceRegisterUtils;
+@Internal
public interface InternalTraceDefinedDataView
extends TraceDefinedDataView, InternalTraceBaseDefinedUnitsView {
+ default TracePlatform getPlatformOf(DataType type) {
+ if (type.getDataTypeManager() instanceof TraceBasedDataTypeManager dtm &&
+ dtm.getTrace() == getTrace()) {
+ return dtm.getPlatform();
+ }
+ /**
+ * TODO: Could we seek a nearest match in terms of data organization? Eh. Maybe not, because
+ * we'd also have to be concerned with whether there's a mapping at the desired address.
+ */
+ return getTrace().getPlatformManager().getHostPlatform();
+ }
+
@Override
- default TraceData create(TracePlatform platform, Lifespan lifespan, Register register,
+ DBTraceDataAdapter create(Lifespan lifespan, Address address, TracePlatform platform,
+ DataType dataType) throws CodeUnitInsertionException;
+
+ @Override
+ DBTraceDataAdapter create(Lifespan lifespan, Address address, TracePlatform platform,
+ DataType dataType, int length) throws CodeUnitInsertionException;
+
+ @Override
+ default DBTraceDataAdapter create(Lifespan lifespan, Address address, DataType dataType,
+ int length) throws CodeUnitInsertionException {
+ return create(lifespan, address, getPlatformOf(dataType), dataType, length);
+ }
+
+ @Override
+ default DBTraceDataAdapter create(Lifespan lifespan, Address address, DataType dataType)
+ throws CodeUnitInsertionException {
+ return create(lifespan, address, getPlatformOf(dataType), dataType);
+ }
+
+ @Override
+ default DBTraceDataAdapter create(TracePlatform platform, Lifespan lifespan, Register register,
DataType dataType) throws CodeUnitInsertionException {
TraceRegisterUtils.requireByteBound(register);
AddressRange range = platform.getConventionalRegisterRange(getSpace(), register);
- return create(lifespan, range.getMinAddress(), dataType, (int) range.getLength());
+ return create(lifespan, range.getMinAddress(), platform, dataType, (int) range.getLength());
}
}
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 e1dbde8334..a4a765d09a 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
@@ -35,7 +35,6 @@ import ghidra.program.model.symbol.SourceType;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.program.model.util.PropertyMap;
import ghidra.trace.database.DBTrace;
-import ghidra.trace.database.guest.InternalTracePlatform;
import ghidra.trace.database.listing.UndefinedDBTraceData;
import ghidra.trace.database.memory.DBTraceMemorySpace;
import ghidra.trace.database.program.DBTraceProgramViewMemory.RegionEntry;
@@ -77,7 +76,6 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
protected final DBTraceProgramView program;
protected final TraceCodeOperations codeOperations;
- protected final InternalTracePlatform platform;
protected final DBTraceProgramViewRootModule rootModule;
protected final Map fragmentsByRegion =
@@ -90,8 +88,7 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
TraceCodeOperations codeOperations) {
this.program = program;
this.codeOperations = codeOperations;
- // TODO: Guest platform views?
- this.platform = program.trace.getPlatformManager().getHostPlatform();
+ // TODO: Map addresses when platform is guest?
this.rootModule = new DBTraceProgramViewRootModule(this);
}
@@ -751,7 +748,7 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
range, s -> s == TraceMemoryState.KNOWN);
long snap = mostRecent == null ? program.snap : mostRecent.getKey().getY2();
return codeOperations.instructions()
- .create(Lifespan.nowOn(snap), addr, platform, prototype, context,
+ .create(Lifespan.nowOn(snap), addr, program.platform, prototype, context,
forcedLengthOverride);
}
@@ -759,7 +756,7 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
public AddressSetView addInstructions(InstructionSet instructionSet, boolean overwrite)
throws CodeUnitInsertionException {
return codeOperations.instructions()
- .addInstructionSet(Lifespan.nowOn(program.snap), platform, instructionSet,
+ .addInstructionSet(Lifespan.nowOn(program.snap), program.platform, instructionSet,
overwrite);
}
@@ -767,12 +764,13 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
public Data createData(Address addr, DataType dataType, int length)
throws CodeUnitInsertionException {
return codeOperations.definedData()
- .create(Lifespan.nowOn(program.snap), addr, dataType, length);
+ .create(Lifespan.nowOn(program.snap), addr, program.platform, dataType, length);
}
@Override
public Data createData(Address addr, DataType dataType) throws CodeUnitInsertionException {
- return codeOperations.definedData().create(Lifespan.nowOn(program.snap), addr, dataType);
+ return codeOperations.definedData()
+ .create(Lifespan.nowOn(program.snap), addr, program.platform, dataType);
}
@Override
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java
index 466e4fd00e..eab47e723c 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java
@@ -45,6 +45,7 @@ import ghidra.program.model.util.AddressSetPropertyMap;
import ghidra.program.model.util.PropertyMapManager;
import ghidra.program.util.*;
import ghidra.trace.database.*;
+import ghidra.trace.database.guest.InternalTracePlatform;
import ghidra.trace.database.listing.DBTraceCodeSpace;
import ghidra.trace.database.listing.DBTraceDefinedUnitsView;
import ghidra.trace.database.memory.DBTraceMemorySpace;
@@ -333,40 +334,40 @@ public class DBTraceProgramView implements TraceProgramView {
range.getX1(), range.getX1(), null, null, null));
}
- private void commentChanged(int commentType, TraceAddressSpace space,
+ private void commentChanged(CommentType commentType, TraceAddressSpace space,
TraceAddressSnapRange range, String oldValue, String newValue) {
DomainObjectEventQueues queues = isVisible(space, range);
if (queues == null) {
return;
}
queues.fireEvent(
- new CommentChangeRecord(commentType, range.getX1(), oldValue, newValue));
+ new CommentChangeRecord(commentType.ordinal(), range.getX1(), oldValue, newValue));
}
private void commentEolChanged(TraceAddressSpace space, TraceAddressSnapRange range,
String oldValue, String newValue) {
- commentChanged(CodeUnit.EOL_COMMENT, space, range, oldValue, newValue);
+ commentChanged(CommentType.EOL, space, range, oldValue, newValue);
}
private void commentPlateChanged(TraceAddressSpace space, TraceAddressSnapRange range,
String oldValue, String newValue) {
- commentChanged(CodeUnit.PLATE_COMMENT, space, range, oldValue, newValue);
+ commentChanged(CommentType.PLATE, space, range, oldValue, newValue);
}
private void commentPostChanged(TraceAddressSpace space, TraceAddressSnapRange range,
String oldValue, String newValue) {
- commentChanged(CodeUnit.POST_COMMENT, space, range, oldValue, newValue);
+ commentChanged(CommentType.POST, space, range, oldValue, newValue);
}
private void commentPreChanged(TraceAddressSpace space, TraceAddressSnapRange range,
String oldValue, String newValue) {
- commentChanged(CodeUnit.PRE_COMMENT, space, range, oldValue, newValue);
+ commentChanged(CommentType.PRE, space, range, oldValue, newValue);
}
private void commentRepeatableChanged(TraceAddressSpace space, TraceAddressSnapRange range,
String oldValue, String newValue) {
// TODO: The "repeatable" semantics are not implemented, yet.
- commentChanged(CodeUnit.REPEATABLE_COMMENT, space, range, oldValue, newValue);
+ commentChanged(CommentType.REPEATABLE, space, range, oldValue, newValue);
}
private void compositeDataAdded(TraceAddressSpace space, TraceAddressSnapRange range,
@@ -697,6 +698,7 @@ public class DBTraceProgramView implements TraceProgramView {
protected final Map regViewsByThread;
protected long snap;
+ protected InternalTracePlatform platform;
protected final DBTraceTimeViewport viewport;
protected final Runnable viewportChangeListener = this::viewportChanged;
@@ -715,6 +717,9 @@ public class DBTraceProgramView implements TraceProgramView {
this.viewport = trace.createTimeViewport();
this.viewport.setSnap(snap);
+ // TODO: Initialize guest platform for fixed views?
+ this.platform = trace.getPlatformManager().getHostPlatform();
+
this.eventQueues = new DomainObjectEventQueues(this, TIME_INTERVAL, trace.getLock());
this.regViewsByThread = new WeakValueHashMap<>();
@@ -833,7 +838,7 @@ public class DBTraceProgramView implements TraceProgramView {
@Override
public TraceBasedDataTypeManager getDataTypeManager() {
- return trace.getDataTypeManager();
+ return platform.getDataTypeManager();
}
@Override
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceVariableSnapProgramView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceVariableSnapProgramView.java
index 9b42c75261..9cf17b3f31 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceVariableSnapProgramView.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceVariableSnapProgramView.java
@@ -4,9 +4,9 @@
* 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.
@@ -18,6 +18,8 @@ package ghidra.trace.database.program;
import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.listing.CodeUnit;
import ghidra.trace.database.DBTrace;
+import ghidra.trace.database.guest.InternalTracePlatform;
+import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.program.TraceVariableSnapProgramView;
/**
@@ -48,4 +50,13 @@ public class DBTraceVariableSnapProgramView extends DBTraceProgramView
// TODO: I could be more particular, but this seems to work fast enough, now.
fireObjectRestored();
}
+
+ @Override
+ public void setPlatform(TracePlatform platform) {
+ if (!(platform instanceof InternalTracePlatform iPlatform) ||
+ platform.getTrace() != trace) {
+ throw new IllegalArgumentException("Platform is not in this trace");
+ }
+ this.platform = iPlatform;
+ }
}
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 03408af765..9e7fa16137 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
@@ -4,9 +4,9 @@
* 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.
@@ -22,6 +22,7 @@ import javax.swing.Icon;
import generic.theme.GIcon;
import ghidra.lifecycle.Transitional;
import ghidra.program.model.address.AddressFactory;
+import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.DataTypeManagerDomainObject;
import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.lang.Language;
@@ -31,6 +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.guest.TracePlatform;
import ghidra.trace.model.guest.TracePlatformManager;
import ghidra.trace.model.listing.TraceCodeManager;
import ghidra.trace.model.listing.TraceCodeUnit;
@@ -95,8 +97,19 @@ public interface Trace extends DataTypeManagerDomainObject {
TraceCodeManager getCodeManager();
+ /**
+ * {@inheritDoc}
+ *
+ *
+ * For traces, this gets the "base" or "host" {@link DataTypeManager}. For platform-specific
+ * managers, see {@link TracePlatform#getDataTypeManager()}.
+ */
@Override
- TraceBasedDataTypeManager getDataTypeManager();
+ default TraceBasedDataTypeManager getDataTypeManager() {
+ return getBaseDataTypeManager();
+ }
+
+ TraceBasedDataTypeManager getBaseDataTypeManager();
TraceEquateManager getEquateManager();
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/data/TraceBasedDataTypeManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/data/TraceBasedDataTypeManager.java
index f3531d6535..855511f559 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/data/TraceBasedDataTypeManager.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/data/TraceBasedDataTypeManager.java
@@ -17,6 +17,7 @@ package ghidra.trace.model.data;
import ghidra.program.model.data.*;
import ghidra.trace.model.Trace;
+import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.program.TraceProgramView;
/**
@@ -36,6 +37,13 @@ public interface TraceBasedDataTypeManager extends ProgramBasedDataTypeManager {
*/
Trace getTrace();
+ /**
+ * Get the platform for which this data type manager is provided
+ *
+ * @return the platform
+ */
+ TracePlatform getPlatform();
+
/**
* TODO: Petition to have this replace
* {@link TraceBasedDataTypeManager#resolve(DataType, DataTypeConflictHandler)}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/guest/TracePlatform.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/guest/TracePlatform.java
index 006180f0b5..c0c44f6983 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/guest/TracePlatform.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/guest/TracePlatform.java
@@ -21,6 +21,7 @@ import ghidra.program.model.address.*;
import ghidra.program.model.lang.*;
import ghidra.program.model.mem.MemBuffer;
import ghidra.trace.model.Trace;
+import ghidra.trace.model.data.TraceBasedDataTypeManager;
import ghidra.trace.model.memory.TraceObjectRegister;
import ghidra.trace.model.symbol.TraceLabelSymbol;
import ghidra.trace.model.target.TraceObject;
@@ -83,10 +84,17 @@ public interface TracePlatform {
/**
* Get the compiler of the guest platform
*
- * @return the compiler spec
+ * @return the compiler specification
*/
CompilerSpec getCompilerSpec();
+ /**
+ * Get the data type manager for this platform.
+ *
+ * @return the data type manager
+ */
+ TraceBasedDataTypeManager getDataTypeManager();
+
/**
* Get the addresses in the host which are mapped to somewhere in the guest
*
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/listing/TraceDefinedDataView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/listing/TraceDefinedDataView.java
index c10a315987..eccc02cdad 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/listing/TraceDefinedDataView.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/listing/TraceDefinedDataView.java
@@ -4,9 +4,9 @@
* 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.
@@ -16,6 +16,7 @@
package ghidra.trace.model.listing;
import ghidra.program.model.address.Address;
+import ghidra.program.model.data.DataOrganization;
import ghidra.program.model.data.DataType;
import ghidra.program.model.lang.Register;
import ghidra.program.model.util.CodeUnitInsertionException;
@@ -29,9 +30,14 @@ import ghidra.trace.model.guest.TracePlatform;
* This view excludes instructions and default / undefined data units.
*/
public interface TraceDefinedDataView extends TraceBaseDefinedUnitsView {
+
/**
* Create a data unit starting at the given address
*
+ *
+ * If the given type is already part of this trace, its platform is used as is. If not, then it
+ * is resolved to the host platform.
+ *
* @param lifespan the span for which the unit is effective
* @param address the starting address
* @param dataType the data type for the unit
@@ -42,12 +48,31 @@ public interface TraceDefinedDataView extends TraceBaseDefinedUnitsView
+ * The given type is resolved to the given platform, even if the type already exists in the
+ * trace by another platform.
+ *
+ * @param lifespan the span for which the unit is effective
+ * @param address the starting address
+ * @param platform the platform for the type's {@link DataOrganization}
+ * @param dataType the data type for the unit
+ * @param length the length of the unit, -1 for unspecified
+ * @return the new data unit
+ * @throws CodeUnitInsertionException if there's a conflict
+ */
+ TraceData create(Lifespan lifespan, Address address, TracePlatform platform, DataType dataType,
+ int length) throws CodeUnitInsertionException;
+
/**
* Create a data unit of unspecified length starting at the given address
*
*
* The length will be determined by the data type, possibly by examining the bytes, e.g., a
- * null-terminated UTF-8 string.
+ * null-terminated UTF-8 string. If the given type is already part of this trace, its platform
+ * is used as is. If not, then it is resolved to the host platform.
*
* @param lifespan the span for which the unit is effective
* @param address the starting address
@@ -58,12 +83,31 @@ public interface TraceDefinedDataView extends TraceBaseDefinedUnitsView
+ * The length will be determined by the data type, possibly by examining the bytes, e.g., a
+ * null-terminated UTF-8 string. The given type is resolved to the given platform, even if the
+ * type already exists in the trace by another platform.
+ *
+ * @param lifespan the span for which the unit is effective
+ * @param address the starting address
+ * @param platform the platform for the type's {@link DataOrganization}
+ * @param dataType the data type for the unit
+ * @return the new data unit
+ * @throws CodeUnitInsertionException if there's a conflict
+ */
+ TraceData create(Lifespan lifespan, Address address, TracePlatform platform, DataType dataType)
+ throws CodeUnitInsertionException;
+
/**
* Create a data unit on the given register
*
*
* If the register is memory mapped, this will delegate to the appropriate space. In those
- * cases, the assignment affects all threads.
+ * cases, the assignment affects all threads. The type is resolved to the host platform, even if
+ * it already exists in the trace by another platform.
*
* @param lifespan the span for which the unit is effective
* @param register the register to assign a data type
@@ -82,7 +126,8 @@ public interface TraceDefinedDataView extends TraceBaseDefinedUnitsView
* If the register is memory mapped, this will delegate to the appropriate space. In those
- * cases, the assignment affects all threads.
+ * cases, the assignment affects all threads. The type is resolved to the given platform, even
+ * if it already exists in the trace by another platform.
*
* @param platform the platform whose language defines the register
* @param lifespan the span for which the unit is effective
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/program/TraceVariableSnapProgramView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/program/TraceVariableSnapProgramView.java
index 67d2d852c0..f845c9b8c4 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/program/TraceVariableSnapProgramView.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/program/TraceVariableSnapProgramView.java
@@ -4,9 +4,9 @@
* 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.
@@ -15,11 +15,13 @@
*/
package ghidra.trace.model.program;
+import ghidra.trace.model.guest.TracePlatform;
+
public interface TraceVariableSnapProgramView extends TraceProgramView {
/**
* Seek to a particular snap
*
- * @param snap
+ * @param snap the snap
*/
void setSnap(long snap);
@@ -29,4 +31,11 @@ public interface TraceVariableSnapProgramView extends TraceProgramView {
default void seekLatest() {
setSnap(getMaxSnap());
}
+
+ /**
+ * Set the current platform, so that actions have context
+ *
+ * @param platform the platform
+ */
+ void setPlatform(TracePlatform platform);
}
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 94d43a0e9e..7c38a1f340 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
@@ -549,6 +549,23 @@ public class ToyDBTraceBuilder implements AutoCloseable {
return code.definedData().create(Lifespan.nowOn(snap), start, type, length);
}
+ /**
+ * Create a data unit
+ *
+ * @param snap the starting snap
+ * @param start the min address
+ * @param platform the platform for data organization
+ * @param type the data type of the unit
+ * @param length the length, or -1 for the type's default
+ * @return the new data unit
+ * @throws CodeUnitInsertionException if the unit cannot be created
+ */
+ public DBTraceDataAdapter addData(long snap, Address start, TracePlatform platform,
+ DataType type, int length) throws CodeUnitInsertionException {
+ DBTraceCodeManager code = trace.getCodeManager();
+ return code.definedData().create(Lifespan.nowOn(snap), start, platform, type, length);
+ }
+
/**
* Create a data unit, first placing the given bytes
*
@@ -569,6 +586,27 @@ public class ToyDBTraceBuilder implements AutoCloseable {
return data;
}
+ /**
+ * Create a data unit, first placing the given bytes
+ *
+ * @param snap the starting snap
+ * @param start the min address
+ * @param platform the platform for data organization
+ * @param type the data type of the unit
+ * @param buf the bytes to place, which will become the unit's bytes
+ * @return the new data unit
+ * @throws CodeUnitInsertionException if the unit cannot be created
+ */
+ public DBTraceDataAdapter addData(long snap, Address start, TracePlatform platform,
+ DataType type, ByteBuffer buf) throws CodeUnitInsertionException {
+ int length = buf.remaining();
+ DBTraceMemoryManager memory = trace.getMemoryManager();
+ memory.putBytes(snap, start, buf);
+ DBTraceDataAdapter data = addData(snap, start, platform, type, length);
+ assertEquals(length, data.getLength());
+ return data;
+ }
+
/**
* Create an instruction unit by disassembling existing bytes
*
@@ -838,6 +876,7 @@ public class ToyDBTraceBuilder implements AutoCloseable {
* Get an object by its path pattern intersecting the given lifespan
*
* @param path the path pattern
+ * @param span the lifespan to search
* @return the object or null
*/
public TraceObject objAny(String path, Lifespan span) {
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/data/DBTraceDataTypeManagerTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/data/DBTraceDataTypeManagerTest.java
index 349a0f67b5..9a4ad26aa6 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/data/DBTraceDataTypeManagerTest.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/data/DBTraceDataTypeManagerTest.java
@@ -4,9 +4,9 @@
* 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.
@@ -46,7 +46,7 @@ public class DBTraceDataTypeManagerTest extends AbstractGhidraHeadlessIntegratio
.getLanguage(
new LanguageID("Toy:BE:64:default"));
trace = new DBTrace("Testing", toyLanguage.getDefaultCompilerSpec(), this);
- dtm = trace.getDataTypeManager();
+ dtm = trace.getBaseDataTypeManager();
}
@After
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 676127b4c6..50ed138f2d 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
@@ -1830,7 +1830,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
@Test
public void testAddGuestInstructionThenRemoveAndDelete() throws AddressOverflowException,
CodeUnitInsertionException, IOException, CancelledException {
- DBTracePlatformManager langMan = b.trace.getPlatformManager();
+ DBTracePlatformManager platMan = b.trace.getPlatformManager();
Language x86 = getSLEIGH_X86_LANGUAGE();
DBTraceGuestPlatform guest;
DBTraceGuestPlatformMappedRange mappedRange;
@@ -1839,7 +1839,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
TraceInstruction i4001;
TraceData d4003;
try (Transaction tx = b.startTransaction()) {
- guest = langMan.addGuestPlatform(x86.getDefaultCompilerSpec());
+ guest = platMan.addGuestPlatform(x86.getDefaultCompilerSpec());
mappedRange = guest.addMappedRange(b.addr(0x0000), b.addr(guest, 0x0000), 1L << 32);
g4000 = b.addInstruction(0, b.addr(0x4000), guest, b.buf(0x90));
i4001 = b.addInstruction(0, b.addr(0x4001), b.host, b.buf(0xf4, 0));
@@ -1857,7 +1857,6 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
b.trace.undo();
// 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.getPlatform());
@@ -1865,13 +1864,66 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
guest.delete(new ConsoleTaskMonitor());
}
assertUndefinedWithAddr(b.addr(0x4000), manager.codeUnits().getAt(0, b.addr(0x4000)));
- // 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)));
+ 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 testAddGuestDataThenRemoveAndDelete() throws Exception {
+ DBTracePlatformManager platMan = b.trace.getPlatformManager();
+ Language x86 = getSLEIGH_X86_LANGUAGE();
+ DBTraceGuestPlatform guest;
+ DBTraceGuestPlatformMappedRange mappedRange;
+
+ TraceData hd4000;
+ TraceData gd4008;
+ TraceData gd400c;
+ try (Transaction tx = b.startTransaction()) {
+ guest = platMan.addGuestPlatform(x86.getDefaultCompilerSpec());
+ mappedRange = guest.addMappedRange(b.addr(0x0000), b.addr(guest, 0x0000), 1L << 32);
+ hd4000 = b.addData(0, b.addr(0x4000), PointerDataType.dataType,
+ b.buf(0, 0, 0, 0, 0, 0, 0x40, 0x80));
+ gd4008 = b.addData(0, b.addr(0x4008), guest, PointerDataType.dataType,
+ b.buf(0x81, 0x40, 0, 0));
+ gd400c = b.addData(0, b.addr(0x400c), gd4008.getDataType(), b.buf(0x82, 0x40, 0, 0));
+ }
+ assertEquals(b.host, hd4000.getPlatform());
+ assertEquals(8, hd4000.getLength());
+ assertEquals(guest, gd4008.getPlatform());
+ assertEquals(4, gd4008.getLength());
+ assertEquals(guest, gd400c.getPlatform());
+ assertEquals(4, gd400c.getLength());
+
+ assertEquals(gd4008, manager.codeUnits().getAt(0, b.addr(0x4008)));
+ assertEquals(gd400c, manager.codeUnits().getAt(0, b.addr(0x400c)));
+
+ try (Transaction tx = b.startTransaction()) {
+ mappedRange.delete(new ConsoleTaskMonitor());
+ }
+ assertEquals(hd4000, manager.codeUnits().getAt(0, b.addr(0x4000)));
+ assertUndefinedWithAddr(b.addr(0x4008), manager.codeUnits().getAt(0, b.addr(0x4008)));
+ assertUndefinedWithAddr(b.addr(0x400c), manager.codeUnits().getAt(0, b.addr(0x400c)));
+
+ b.trace.undo();
+
+ // NB. The range deletion also deletes the guest units, so they'll have new identities
+ gd4008 = manager.definedData().getAt(0, b.addr(0x4008));
+ gd400c = manager.definedData().getAt(0, b.addr(0x400c));
+ assertNotNull(gd4008);
+ assertNotNull(gd400c);
+ assertEquals(guest, gd4008.getPlatform());
+ assertEquals(guest, gd400c.getPlatform());
+ try (Transaction tx = b.startTransaction()) {
+ guest.delete(new ConsoleTaskMonitor());
+ }
+ assertEquals(hd4000, manager.codeUnits().getAt(0, b.addr(0x4000)));
+ assertUndefinedWithAddr(b.addr(0x4008), manager.codeUnits().getAt(0, b.addr(0x4008)));
+ assertUndefinedWithAddr(b.addr(0x400c), manager.codeUnits().getAt(0, b.addr(0x400c)));
+ assertNotNull(manager.definedData().getAt(0, b.addr(0x4000)));
+ }
+
@Test
public void testSaveAndLoad() throws Exception {
try (Transaction tx = b.startTransaction()) {
diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/generic/depends/DependentServiceResolver.java b/Ghidra/Debug/ProposedUtils/src/main/java/generic/depends/DependentServiceResolver.java
index a959410ecd..87b71b2366 100644
--- a/Ghidra/Debug/ProposedUtils/src/main/java/generic/depends/DependentServiceResolver.java
+++ b/Ghidra/Debug/ProposedUtils/src/main/java/generic/depends/DependentServiceResolver.java
@@ -4,9 +4,9 @@
* 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.
@@ -17,7 +17,6 @@ package generic.depends;
import java.lang.reflect.*;
import java.util.*;
-import java.util.Map.Entry;
import generic.depends.err.*;
@@ -137,6 +136,7 @@ public class DependentServiceResolver {
public void injectServices(T obj) throws ServiceConstructionException {
Map, Object> instancesByClass = new HashMap<>();
Map constructed = new HashMap<>();
+ Map, Set> fieldsByClass = new HashMap<>(this.fieldsByClass);
for (DependentServiceConstructor> cons : ordered) {
Object service = constructed.get(cons.method);
if (service == null) {
@@ -144,16 +144,18 @@ public class DependentServiceResolver {
constructed.put(cons.method, service);
}
instancesByClass.put(cons.cls, service);
- }
- for (Entry, Set> entry : fieldsByClass.entrySet()) {
- for (Field f : entry.getValue()) {
+ for (Field f : fieldsByClass.remove(cons.cls)) {
try {
- f.set(obj, instancesByClass.get(entry.getKey()));
+ f.set(obj, service);
}
catch (IllegalArgumentException | IllegalAccessException e) {
throw new AssertionError(e);
}
}
}
+ if (!fieldsByClass.isEmpty()) {
+ throw new ServiceConstructionException(
+ "No service constructor for " + fieldsByClass.keySet(), null);
+ }
}
}