diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/DebuggerCoordinates.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/DebuggerCoordinates.java index c279f1ed6d..2b7ac76404 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/DebuggerCoordinates.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/DebuggerCoordinates.java @@ -33,6 +33,7 @@ import ghidra.framework.plugintool.PluginTool; import ghidra.trace.database.DBTraceContentHandler; import ghidra.trace.database.DBTraceUtils; import ghidra.trace.model.Trace; +import ghidra.trace.model.guest.TracePlatform; import ghidra.trace.model.program.TraceProgramView; import ghidra.trace.model.stack.*; import ghidra.trace.model.target.TraceObject; @@ -49,7 +50,7 @@ import ghidra.util.NotOwnerException; public class DebuggerCoordinates { public static final DebuggerCoordinates NOWHERE = - new DebuggerCoordinates(null, null, null, null, null, null, null); + new DebuggerCoordinates(null, null, null, null, null, null, null, null); private static final String KEY_TRACE_PROJ_LOC = "TraceProjLoc"; private static final String KEY_TRACE_PROJ_NAME = "TraceProjName"; @@ -65,6 +66,9 @@ public class DebuggerCoordinates { if (!Objects.equals(a.trace, b.trace)) { return false; } + if (!Objects.equals(a.platform, b.platform)) { + return false; + } if (!Objects.equals(a.thread, b.thread)) { return false; } @@ -82,6 +86,7 @@ public class DebuggerCoordinates { } private final Trace trace; + private final TracePlatform platform; private final TraceRecorder recorder; private final TraceThread thread; private final TraceProgramView view; @@ -94,9 +99,11 @@ public class DebuggerCoordinates { private Long viewSnap; private DefaultTraceTimeViewport viewport; - DebuggerCoordinates(Trace trace, TraceRecorder recorder, TraceThread thread, - TraceProgramView view, TraceSchedule time, Integer frame, TraceObject object) { + DebuggerCoordinates(Trace trace, TracePlatform platform, TraceRecorder recorder, + TraceThread thread, TraceProgramView view, TraceSchedule time, Integer frame, + TraceObject object) { this.trace = trace; + this.platform = platform; this.recorder = recorder; this.thread = thread; this.view = view; @@ -151,6 +158,10 @@ public class DebuggerCoordinates { return hash; } + private static TracePlatform resolvePlatform(Trace trace) { + return trace.getPlatformManager().getHostPlatform(); + } + private static TraceThread resolveThread(Trace trace, TraceSchedule time) { long snap = time.getSnap(); return trace.getThreadManager() @@ -186,13 +197,14 @@ public class DebuggerCoordinates { return this; } if (trace == null) { + TracePlatform newPlatform = resolvePlatform(newTrace); TraceThread newThread = resolveThread(newTrace); TraceProgramView newView = resolveView(newTrace); TraceSchedule newTime = null; // Allow later resolution Integer newFrame = resolveFrame(newThread, newTime); TraceObject newObject = resolveObject(newTrace); - return new DebuggerCoordinates(newTrace, null, newThread, newView, newTime, newFrame, - newObject); + return new DebuggerCoordinates(newTrace, newPlatform, null, newThread, newView, newTime, + newFrame, newObject); } throw new IllegalArgumentException("Cannot change trace"); } @@ -241,24 +253,54 @@ public class DebuggerCoordinates { return resolveObject(recorder.getTrace(), recorder.getFocus()); } + public DebuggerCoordinates platform(TracePlatform newPlatform) { + if (platform == newPlatform) { + return this; + } + if (newPlatform == null) { + if (trace == null) { + return NOWHERE; + } + return new DebuggerCoordinates(trace, resolvePlatform(trace), recorder, thread, view, + time, frame, object); + } + if (trace == null) { + Trace newTrace = newPlatform.getTrace(); + TraceThread newThread = resolveThread(newTrace); + TraceProgramView newView = resolveView(newTrace); + TraceSchedule newTime = null; // Allow later resolution + Integer newFrame = resolveFrame(newThread, newTime); + TraceObject newObject = resolveObject(newTrace); + return new DebuggerCoordinates(newTrace, newPlatform, null, newThread, newView, newTime, + newFrame, newObject); + } + if (trace != newPlatform.getTrace()) { + throw new IllegalArgumentException("Cannot change trace"); + } + return new DebuggerCoordinates(trace, newPlatform, recorder, thread, view, time, frame, + object); + } + public DebuggerCoordinates recorder(TraceRecorder newRecorder) { if (recorder == newRecorder) { return this; } if (newRecorder == null) { - return new DebuggerCoordinates(trace, newRecorder, thread, view, time, frame, object); + return new DebuggerCoordinates(trace, platform, newRecorder, thread, view, time, frame, + object); } if (newRecorder != null && trace != null && newRecorder.getTrace() != trace) { throw new IllegalArgumentException("Cannot change trace"); } Trace newTrace = trace != null ? trace : newRecorder.getTrace(); + TracePlatform newPlatform = platform != null ? platform : resolvePlatform(newTrace); TraceSchedule newTime = time != null ? time : TraceSchedule.snap(newRecorder.getSnap()); TraceThread newThread = thread != null ? thread : resolveThread(newRecorder, newTime); TraceProgramView newView = view != null ? view : resolveView(newTrace, newTime); Integer newFrame = frame != null ? frame : resolveFrame(newRecorder, newThread, newTime); TraceObject newObject = object != null ? object : resolveObject(newRecorder, newTime); - return new DebuggerCoordinates(newTrace, newRecorder, newThread, newView, newTime, newFrame, - newObject); + return new DebuggerCoordinates(newTrace, newPlatform, newRecorder, newThread, newView, + newTime, newFrame, newObject); } public DebuggerCoordinates reFindThread() { @@ -314,6 +356,7 @@ public class DebuggerCoordinates { newThread = resolveThread(recorder, getTime()); } Trace newTrace = trace != null ? trace : newThread.getTrace(); + TracePlatform newPlatform = platform != null ? platform : resolvePlatform(newTrace); TraceSchedule newTime = time != null ? time : resolveTime(view); TraceProgramView newView = view != null ? view : resolveView(newTrace, newTime); // Yes, override frame with 0 on thread changes, unless target says otherwise @@ -322,8 +365,8 @@ public class DebuggerCoordinates { TraceObject ancestor = resolveObject(newThread, newFrame, newTime); TraceObject newObject = object != null && isAncestor(ancestor, object, newTime) ? object : ancestor; - return new DebuggerCoordinates(newTrace, recorder, newThread, newView, newTime, newFrame, - newObject); + return new DebuggerCoordinates(newTrace, newPlatform, recorder, newThread, newView, newTime, + newFrame, newObject); } /** @@ -348,8 +391,8 @@ public class DebuggerCoordinates { TraceObject ancestor = resolveObject(newThread, newFrame, newTime); TraceObject newObject = object != null && isAncestor(ancestor, object, newTime) ? object : ancestor; - return new DebuggerCoordinates(trace, recorder, newThread, view, newTime, newFrame, - newObject); + return new DebuggerCoordinates(trace, platform, recorder, newThread, view, newTime, + newFrame, newObject); } public DebuggerCoordinates frame(int newFrame) { @@ -362,11 +405,13 @@ public class DebuggerCoordinates { TraceObject ancestor = resolveObject(thread, newFrame, getTime()); TraceObject newObject = object != null && isAncestor(ancestor, object, getTime()) ? object : ancestor; - return new DebuggerCoordinates(trace, recorder, thread, view, time, newFrame, newObject); + return new DebuggerCoordinates(trace, platform, recorder, thread, view, time, newFrame, + newObject); } private DebuggerCoordinates replaceView(TraceProgramView newView) { - return new DebuggerCoordinates(trace, recorder, thread, newView, time, frame, object); + return new DebuggerCoordinates(trace, platform, recorder, thread, newView, time, frame, + object); } private static TraceSchedule resolveTime(TraceProgramView view) { @@ -430,7 +475,7 @@ public class DebuggerCoordinates { } else { if (newObject == null) { - return new DebuggerCoordinates(trace, recorder, thread, view, time, frame, + return new DebuggerCoordinates(trace, platform, recorder, thread, view, time, frame, newObject); } if (newObject.getTrace() != trace) { @@ -438,11 +483,12 @@ public class DebuggerCoordinates { } newTrace = trace; } + TracePlatform newPlatform = resolvePlatform(newTrace); TraceThread newThread = resolveThread(newObject); Integer newFrame = resolveFrame(newObject); - return new DebuggerCoordinates(newTrace, recorder, newThread, view, time, newFrame, - newObject); + return new DebuggerCoordinates(newTrace, newPlatform, recorder, newThread, view, time, + newFrame, newObject); } protected static TraceThread resolveThread(TraceRecorder recorder, TargetObject targetObject) { @@ -463,7 +509,8 @@ public class DebuggerCoordinates { } TraceThread newThread = resolveThread(recorder, targetObject); Integer newFrame = resolveFrame(recorder, targetObject); - return new DebuggerCoordinates(trace, recorder, newThread, view, time, newFrame, null); + return new DebuggerCoordinates(trace, platform, recorder, newThread, view, time, newFrame, + null); } public DebuggerCoordinates object(TargetObject newObject) { @@ -474,6 +521,10 @@ public class DebuggerCoordinates { return trace; } + public TracePlatform getPlatform() { + return platform; + } + public TraceRecorder getRecorder() { return recorder; } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerGoToTrait.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerGoToTrait.java index 2f9b60f594..b10c0fba4f 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerGoToTrait.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerGoToTrait.java @@ -31,7 +31,7 @@ import ghidra.pcode.utils.Utils; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSpace; import ghidra.program.model.lang.Language; -import ghidra.trace.model.program.TraceProgramView; +import ghidra.trace.model.guest.TracePlatform; public abstract class DebuggerGoToTrait { protected DockingAction action; @@ -68,19 +68,13 @@ public abstract class DebuggerGoToTrait { } private void activatedGoTo(ActionContext context) { - TraceProgramView view = current.getView(); - if (view == null) { - return; - } - Language language = view.getLanguage(); - if (!(language instanceof SleighLanguage)) { - return; - } - goToDialog.show((SleighLanguage) language); + TracePlatform platform = current.getPlatform(); + goToDialog.show((SleighLanguage) platform.getLanguage()); } public CompletableFuture goToSleigh(String spaceName, String expression) { - Language language = current.getView().getLanguage(); + TracePlatform platform = current.getPlatform(); + Language language = platform.getLanguage(); if (!(language instanceof SleighLanguage)) { throw new IllegalStateException("Current trace does not use Sleigh"); } @@ -90,17 +84,18 @@ public abstract class DebuggerGoToTrait { throw new IllegalArgumentException("No such address space: " + spaceName); } PcodeExpression expr = SleighProgramCompiler.compileExpression(slang, expression); - return goToSleigh(space, expr); + return goToSleigh(platform, space, expr); } - public CompletableFuture goToSleigh(AddressSpace space, PcodeExpression expression) { + public CompletableFuture goToSleigh(TracePlatform platform, AddressSpace space, + PcodeExpression expression) { PcodeExecutor executor = DebuggerPcodeUtils.executorForCoordinates(tool, current); CompletableFuture result = CompletableFuture.supplyAsync(() -> expression.evaluate(executor)); return result.thenApplyAsync(offset -> { Address address = space.getAddress( Utils.bytesToLong(offset, offset.length, expression.getLanguage().isBigEndian())); - return goToAddress(address); + return goToAddress(platform.mapGuestToHost(address)); }, AsyncUtils.SWING_EXECUTOR); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/watch/DebuggerWatchesProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/watch/DebuggerWatchesProvider.java index 27ec9e9297..303130ce9b 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/watch/DebuggerWatchesProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/watch/DebuggerWatchesProvider.java @@ -209,7 +209,7 @@ public class DebuggerWatchesProvider extends ComponentProviderAdapter { } protected static boolean sameCoordinates(DebuggerCoordinates a, DebuggerCoordinates b) { - if (!Objects.equals(a.getTrace(), b.getTrace())) { + if (!Objects.equals(a.getPlatform(), b.getPlatform())) { return false; } if (!Objects.equals(a.getRecorder(), b.getRecorder())) { @@ -543,7 +543,7 @@ public class DebuggerWatchesProvider extends ComponentProviderAdapter { protected boolean selHasMemoryReads(DebuggerWatchActionContext ctx) { for (WatchRow row : ctx.getWatchRows()) { - AddressSet set = row.getReads(); + AddressSetView set = row.getReads(); if (set == null) { continue; } @@ -634,7 +634,7 @@ public class DebuggerWatchesProvider extends ComponentProviderAdapter { } AddressSet sel = new AddressSet(); for (WatchRow row : context.getWatchRows()) { - AddressSet reads = row.getReads(); + AddressSetView reads = row.getReads(); if (reads != null) { sel.add(reads); } @@ -858,7 +858,7 @@ public class DebuggerWatchesProvider extends ComponentProviderAdapter { public synchronized void doCheckDepsAndReevaluate() { for (WatchRow row : watchTableModel.getModelData()) { - AddressSet reads = row.getReads(); + AddressSetView reads = row.getReads(); if (reads == null || reads.intersects(changed)) { row.doTargetReads(); row.reevaluate(); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/watch/WatchRow.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/watch/WatchRow.java index f08cbb1544..09da1e4c0a 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/watch/WatchRow.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/watch/WatchRow.java @@ -31,7 +31,6 @@ import ghidra.app.services.DebuggerStateEditingService.StateEditor; import ghidra.docking.settings.Settings; import ghidra.docking.settings.SettingsImpl; import ghidra.framework.options.SaveState; -import ghidra.framework.plugintool.PluginTool; import ghidra.pcode.exec.*; import ghidra.pcode.exec.trace.*; import ghidra.pcode.utils.Utils; @@ -76,7 +75,7 @@ public class WatchRow { private TraceMemoryState state; private Address address; private Symbol symbol; - private AddressSet reads; + private AddressSetView reads; private byte[] value; private byte[] prevValue; // Value at previous coordinates private String valueString; @@ -140,12 +139,14 @@ public class WatchRow { Pair valueWithState = compiled.evaluate(executorWithState); Pair valueWithAddress = compiled.evaluate(executorWithAddress); + TracePlatform platform = provider.current.getPlatform(); value = valueWithState.getLeft(); error = null; state = valueWithState.getRight(); - address = valueWithAddress.getRight(); + // TODO: Optional column for guest address? + address = platform.mapGuestToHost(valueWithAddress.getRight()); symbol = computeSymbol(); - reads = executorWithAddress.getReads(); + reads = platform.mapGuestToHost(executorWithAddress.getReads()); valueObj = parseAsDataTypeObj(); valueString = parseAsDataTypeStr(); @@ -245,26 +246,24 @@ public class WatchRow { * the computation. The resulting pair gives the value and its address. To get the addresses * involved, invoke {@link ReadDepsPcodeExecutor#getReads()} after evaluation. * - * @param tool the plugin tool * @param coordinates the coordinates providing context for the evaluation * @return an executor for evaluating the watch */ - protected static ReadDepsPcodeExecutor buildAddressDepsExecutor(PluginTool tool, + protected static ReadDepsPcodeExecutor buildAddressDepsExecutor( DebuggerCoordinates coordinates) { - Trace trace = coordinates.getTrace(); - TracePlatform platform = DebuggerPcodeUtils.getCurrentPlatform(tool, coordinates); + TracePlatform platform = coordinates.getPlatform(); ReadDepsTraceBytesPcodeExecutorStatePiece piece = new ReadDepsTraceBytesPcodeExecutorStatePiece(platform, coordinates.getViewSnap(), coordinates.getThread(), coordinates.getFrame()); - Language language = trace.getBaseLanguage(); - if (!(language instanceof SleighLanguage)) { - throw new IllegalArgumentException("Watch expressions require a SLEIGH language"); + Language language = platform.getLanguage(); + if (!(language instanceof SleighLanguage slang)) { + throw new IllegalArgumentException("Watch expressions require a Sleigh language"); } PcodeExecutorState> paired = new DefaultPcodeExecutorState<>(piece) .paired(new AddressOfPcodeExecutorStatePiece(language)); PairedPcodeArithmetic arithmetic = new PairedPcodeArithmetic<>( BytesPcodeArithmetic.forLanguage(language), AddressOfPcodeArithmetic.INSTANCE); - return new ReadDepsPcodeExecutor(piece, (SleighLanguage) language, arithmetic, paired); + return new ReadDepsPcodeExecutor(piece, slang, arithmetic, paired); } public void setCoordinates(DebuggerCoordinates coordinates) { @@ -292,7 +291,7 @@ public class WatchRow { } executorWithState = TraceSleighUtils.buildByteWithStateExecutor(trace, coordinates.getViewSnap(), coordinates.getThread(), coordinates.getFrame()); - executorWithAddress = buildAddressDepsExecutor(provider.getTool(), coordinates); + executorWithAddress = buildAddressDepsExecutor(coordinates); } public void setExpression(String expression) { @@ -423,7 +422,12 @@ public class WatchRow { return "{ " + NumericUtilities.convertBytesToString(value, " ") + " }"; } - public AddressSet getReads() { + /** + * Get the memory read by the watch, from the host platform perspective + * + * @return the reads + */ + public AddressSetView getReads() { return reads; } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/DebuggerEmulationServicePlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/DebuggerEmulationServicePlugin.java index cd655ced9c..c0a70c0b71 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/DebuggerEmulationServicePlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/DebuggerEmulationServicePlugin.java @@ -43,7 +43,6 @@ import ghidra.async.AsyncLazyMap; import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.annotation.AutoServiceConsumed; import ghidra.framework.plugintool.util.PluginStatus; -import ghidra.pcode.exec.DebuggerPcodeUtils; import ghidra.program.model.address.Address; import ghidra.program.model.listing.Program; import ghidra.program.util.ProgramLocation; @@ -464,8 +463,8 @@ public class DebuggerEmulationServicePlugin extends Plugin implements DebuggerEm * TODO: object and/or platform should somehow be incorporated into the key, the schedule? * something? */ - TracePlatform platform = DebuggerPcodeUtils.getCurrentPlatform(platformService, - traceManager.getCurrentFor(trace).trace(trace)); + DebuggerCoordinates current = traceManager.resolveTrace(trace); + TracePlatform platform = current.getPlatform(); TraceSchedule time = key.time; CachedEmulator ce; 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 f3564b45d0..5b876ae519 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 @@ -31,6 +31,7 @@ import ghidra.app.plugin.core.debug.DebuggerCoordinates; import ghidra.app.plugin.core.debug.DebuggerPluginPackage; import ghidra.app.plugin.core.debug.event.*; import ghidra.app.plugin.core.debug.gui.DebuggerResources.*; +import ghidra.app.plugin.core.debug.mapping.DebuggerPlatformMapper; import ghidra.app.services.*; import ghidra.async.*; import ghidra.async.AsyncConfigFieldCodec.BooleanAsyncConfigFieldCodec; @@ -48,6 +49,7 @@ import ghidra.lifecycle.Internal; import ghidra.trace.model.Trace; import ghidra.trace.model.Trace.TraceThreadChangeType; import ghidra.trace.model.TraceDomainObjectListener; +import ghidra.trace.model.guest.TracePlatform; import ghidra.trace.model.program.TraceProgramView; import ghidra.trace.model.program.TraceVariableSnapProgramView; import ghidra.trace.model.stack.TraceStackFrame; @@ -75,6 +77,7 @@ import ghidra.util.task.*; TraceClosedPluginEvent.class, ModelObjectFocusedPluginEvent.class, TraceRecorderAdvancedPluginEvent.class, + DebuggerPlatformPluginEvent.class, }, servicesRequired = {}, servicesProvided = { @@ -504,6 +507,23 @@ public class DebuggerTraceManagerServicePlugin extends Plugin activateSnap(snap); } + protected void doPlatformMapperSelected(Trace trace, DebuggerPlatformMapper mapper) { + synchronized (listenersByTrace) { + if (!listenersByTrace.containsKey(trace)) { + return; + } + DebuggerCoordinates cur = + lastCoordsByTrace.getOrDefault(trace, DebuggerCoordinates.NOWHERE); + DebuggerCoordinates adj = cur.platform( + trace.getPlatformManager().getPlatform(mapper.getCompilerSpec(cur.getObject()))); + lastCoordsByTrace.put(trace, adj); + if (trace == current.getTrace()) { + current = adj; + fireLocationEvent(adj); + } + } + } + protected TraceRecorder computeRecorder(Trace trace) { if (modelService == null) { return null; @@ -531,25 +551,24 @@ public class DebuggerTraceManagerServicePlugin extends Plugin @Override public void processEvent(PluginEvent event) { super.processEvent(event); - if (event instanceof TraceActivatedPluginEvent) { - TraceActivatedPluginEvent ev = (TraceActivatedPluginEvent) event; + if (event instanceof TraceActivatedPluginEvent ev) { synchronized (listenersByTrace) { doSetCurrent(ev.getActiveCoordinates()); } } - else if (event instanceof TraceClosedPluginEvent) { - TraceClosedPluginEvent ev = (TraceClosedPluginEvent) event; + else if (event instanceof TraceClosedPluginEvent ev) { doTraceClosed(ev.getTrace()); } - else if (event instanceof ModelObjectFocusedPluginEvent) { - ModelObjectFocusedPluginEvent ev = (ModelObjectFocusedPluginEvent) event; + else if (event instanceof ModelObjectFocusedPluginEvent ev) { doModelObjectFocused(ev.getFocus(), true); } - else if (event instanceof TraceRecorderAdvancedPluginEvent) { - TraceRecorderAdvancedPluginEvent ev = (TraceRecorderAdvancedPluginEvent) event; - TimedMsg.debug(this, "Processing trace-advanced event"); + else if (event instanceof TraceRecorderAdvancedPluginEvent ev) { + // TimedMsg.debug(this, "Processing trace-advanced event"); doTraceRecorderAdvanced(ev.getRecorder(), ev.getSnap()); } + else if (event instanceof DebuggerPlatformPluginEvent ev) { + doPlatformMapperSelected(ev.getTrace(), ev.getMapper()); + } } @Override @@ -576,6 +595,11 @@ public class DebuggerTraceManagerServicePlugin extends Plugin return current.getTrace(); } + @Override + public TracePlatform getCurrentPlatform() { + return current.getPlatform(); + } + @Override public TraceProgramView getCurrentView() { return current.getView(); @@ -1006,6 +1030,12 @@ public class DebuggerTraceManagerServicePlugin extends Plugin return getCurrentFor(trace).trace(trace); } + @Override + public DebuggerCoordinates resolvePlatform(TracePlatform platform) { + Trace trace = platform == null ? null : platform.getTrace(); + return getCurrentFor(trace).platform(platform); + } + @Override public DebuggerCoordinates resolveThread(TraceThread thread) { Trace trace = thread == null ? null : thread.getTrace(); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/services/DebuggerTraceManagerService.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/services/DebuggerTraceManagerService.java index bb6748e3d1..23b9593227 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/services/DebuggerTraceManagerService.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/services/DebuggerTraceManagerService.java @@ -25,6 +25,7 @@ import ghidra.framework.model.DomainFile; import ghidra.framework.plugintool.ServiceInfo; import ghidra.program.model.listing.Program; import ghidra.trace.model.Trace; +import ghidra.trace.model.guest.TracePlatform; import ghidra.trace.model.program.TraceProgramView; import ghidra.trace.model.target.TraceObject; import ghidra.trace.model.thread.TraceThread; @@ -89,6 +90,13 @@ public interface DebuggerTraceManagerService { */ Trace getCurrentTrace(); + /** + * Get the active platform + * + * @return the active platform, or null + */ + TracePlatform getCurrentPlatform(); + /** * Get the active view * @@ -263,6 +271,24 @@ public interface DebuggerTraceManagerService { activate(resolveTrace(trace)); } + /** + * Resolve coordinates for the given platform using the manager's "best judgment" + * + * @see #resolveTrace(Trace) + * @param platform the platform + * @return the best coordinates + */ + DebuggerCoordinates resolvePlatform(TracePlatform platform); + + /** + * Activate the given platform + * + * @param platform the desired platform + */ + default void activatePlatform(TracePlatform platform) { + activate(resolvePlatform(platform)); + } + /** * Resolve coordinates for the given thread using the manager's "best judgment" * diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/pcode/exec/DebuggerPcodeUtils.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/pcode/exec/DebuggerPcodeUtils.java index fa41349cb8..2e0d4a7cde 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/pcode/exec/DebuggerPcodeUtils.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/pcode/exec/DebuggerPcodeUtils.java @@ -15,15 +15,10 @@ */ package ghidra.pcode.exec; -import java.util.Objects; - import ghidra.app.plugin.core.debug.DebuggerCoordinates; -import ghidra.app.plugin.core.debug.mapping.DebuggerPlatformMapper; import ghidra.app.plugin.core.debug.service.emulation.*; import ghidra.app.plugin.core.debug.service.emulation.data.DefaultPcodeDebuggerAccess; import ghidra.app.plugin.processors.sleigh.SleighLanguage; -import ghidra.app.services.DebuggerPlatformService; -import ghidra.app.services.DebuggerTraceManagerService; import ghidra.framework.plugintool.PluginTool; import ghidra.pcode.emu.ThreadPcodeExecutorState; import ghidra.program.model.lang.Language; @@ -36,45 +31,6 @@ import ghidra.trace.model.guest.TracePlatform; public enum DebuggerPcodeUtils { ; - /** - * Get the current platform - * - *

- * TODO: This should be part of {@link DebuggerTraceManagerService}. - * - * @param platformService the platform service - * @param coordinates the coordinates - * @return the "current platform" for the coordinates - */ - public static TracePlatform getCurrentPlatform(DebuggerPlatformService platformService, - DebuggerCoordinates coordinates) { - Trace trace = coordinates.getTrace(); - if (platformService == null) { - return trace.getPlatformManager().getHostPlatform(); - } - DebuggerPlatformMapper mapper = platformService.getCurrentMapperFor(trace); - if (mapper == null) { - return trace.getPlatformManager().getHostPlatform(); - } - return Objects.requireNonNull(trace.getPlatformManager() - .getPlatform(mapper.getCompilerSpec(coordinates.getObject()))); - } - - /** - * Get the current platform - * - *

- * TODO: This should be part of {@link DebuggerTraceManagerService}. - * - * @param tool the plugin tool - * @param coordinates the coordinates - * @return the "current platform" for the coordinates - */ - public static TracePlatform getCurrentPlatform(PluginTool tool, - DebuggerCoordinates coordinates) { - return getCurrentPlatform(tool.getService(DebuggerPlatformService.class), coordinates); - } - /** * Get a p-code executor state for the given coordinates * @@ -93,7 +49,7 @@ public enum DebuggerPcodeUtils { if (trace == null) { throw new IllegalArgumentException("Coordinates have no trace"); } - TracePlatform platform = getCurrentPlatform(tool, coordinates); + TracePlatform platform = coordinates.getPlatform(); Language language = platform.getLanguage(); if (!(language instanceof SleighLanguage)) { throw new IllegalArgumentException( 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 956e351005..080e5d8887 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 @@ -18,6 +18,7 @@ package ghidra.app.plugin.core.debug.service.emulation; import static org.junit.Assert.*; import java.math.BigInteger; +import java.nio.ByteBuffer; import java.util.concurrent.CompletableFuture; import org.junit.Before; @@ -28,18 +29,23 @@ import com.google.common.collect.Range; import generic.Unique; import generic.test.category.NightlyCategory; -import ghidra.app.plugin.assembler.Assembler; -import ghidra.app.plugin.assembler.Assemblers; +import ghidra.app.plugin.assembler.*; import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin; import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest; +import ghidra.app.plugin.core.debug.mapping.DebuggerPlatformMapper; +import ghidra.app.plugin.core.debug.mapping.DebuggerPlatformOpinion; +import ghidra.app.plugin.core.debug.service.platform.DebuggerPlatformServicePlugin; import ghidra.app.services.DebuggerStaticMappingService; +import ghidra.pcode.utils.Utils; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSpace; import ghidra.program.model.lang.*; import ghidra.program.model.mem.Memory; import ghidra.program.model.mem.MemoryBlock; import ghidra.program.util.ProgramLocation; -import ghidra.trace.model.*; +import ghidra.trace.model.DefaultTraceLocation; +import ghidra.trace.model.Trace; +import ghidra.trace.model.guest.TracePlatform; import ghidra.trace.model.memory.TraceMemoryManager; import ghidra.trace.model.memory.TraceMemorySpace; import ghidra.trace.model.thread.TraceThread; @@ -278,4 +284,55 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerGU assertEquals("deadbeefcafebabe", regs.getViewValue(scratch, tb.reg("RAX")).getUnsignedValue().toString(16)); } + + @Test + public void testEmulationGuest() throws Throwable { + DebuggerPlatformServicePlugin platformPlugin = + addPlugin(tool, DebuggerPlatformServicePlugin.class); + + createTrace(); + + Language x64 = getSLEIGH_X86_64_LANGUAGE(); + Assembler asm = Assemblers.getAssembler(x64); + AssemblyBuffer buf = new AssemblyBuffer(asm, tb.addr(x64, 0x00400000)); + TraceMemoryManager mem = tb.trace.getMemoryManager(); + TraceThread thread; + try (UndoableTransaction tid = tb.startTransaction()) { + thread = tb.getOrAddThread("Threads[0]", 0); + buf.assemble("MOV RAX, qword ptr [0x00600800]"); + mem.putBytes(0, tb.addr(0x00400000), ByteBuffer.wrap(buf.getBytes())); + mem.putBytes(0, tb.addr(0x00600800), + ByteBuffer.wrap(Utils.longToBytes(0xdeadbeefcafebabeL, 8, false))); + } + traceManager.openTrace(tb.trace); + traceManager.activateTrace(tb.trace); + waitForSwing(); + + CompilerSpec x64Default = x64.getDefaultCompilerSpec(); + DebuggerPlatformMapper mapper = + DebuggerPlatformOpinion.queryOpinions(tb.trace, null, 0, true) + .stream() + .filter(o -> x64.getLanguageID().equals(o.getLanguageID())) + .filter(o -> x64Default.getCompilerSpecID().equals(o.getCompilerSpecID())) + .findAny() + .orElse(null) + .take(tool, tb.trace); + platformPlugin.setCurrentMapperFor(tb.trace, mapper, 0); + waitForSwing(); + + waitForPass(() -> assertEquals(x64, traceManager.getCurrentPlatform().getLanguage())); + TracePlatform platform = traceManager.getCurrentPlatform(); + + try (UndoableTransaction tid = tb.startTransaction()) { + tb.exec(platform, 0, thread, 0, "RIP = 0x00400000;"); + } + + long scratch = + emulationPlugin.emulate(tb.trace, TraceSchedule.parse("0:t0-1"), TaskMonitor.DUMMY); + TraceMemorySpace regs = mem.getMemoryRegisterSpace(thread, false); + assertEquals("deadbeefcafebabe", + regs.getViewValue(platform, scratch, tb.reg(platform, "RAX")) + .getUnsignedValue() + .toString(16)); + } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceMemoryManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceMemoryManager.java index 0cc3f4fad8..3b55763460 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceMemoryManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceMemoryManager.java @@ -266,7 +266,8 @@ public class DBTraceMemoryManager extends AbstractDBTraceSpaceBasedManager getViewState(long snap, Address address) { - return delegateRead(address.getAddressSpace(), m -> m.getViewState(snap, address)); + return delegateReadOr(address.getAddressSpace(), m -> m.getViewState(snap, address), + () -> Map.entry(snap, TraceMemoryState.UNKNOWN)); } @Override diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/pcode/emu/DefaultPcodeThread.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/pcode/emu/DefaultPcodeThread.java index 6eb63f3123..3e991e686a 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/pcode/emu/DefaultPcodeThread.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/pcode/emu/DefaultPcodeThread.java @@ -225,7 +225,8 @@ public class DefaultPcodeThread implements PcodeThread { this.library = createUseropLibrary(); this.executor = createExecutor(); - this.pc = language.getProgramCounter(); + this.pc = + Objects.requireNonNull(language.getProgramCounter(), "Language has no program counter"); this.contextreg = language.getContextBaseRegister(); if (contextreg != Register.NO_CONTEXT) {