GP-2522: Add platform to DebuggerCoordinates

This commit is contained in:
Dan 2022-09-20 11:14:09 -04:00
parent 89b0f92e50
commit e0730a31b7
11 changed files with 232 additions and 112 deletions

View file

@ -33,6 +33,7 @@ import ghidra.framework.plugintool.PluginTool;
import ghidra.trace.database.DBTraceContentHandler; import ghidra.trace.database.DBTraceContentHandler;
import ghidra.trace.database.DBTraceUtils; import ghidra.trace.database.DBTraceUtils;
import ghidra.trace.model.Trace; import ghidra.trace.model.Trace;
import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.program.TraceProgramView; import ghidra.trace.model.program.TraceProgramView;
import ghidra.trace.model.stack.*; import ghidra.trace.model.stack.*;
import ghidra.trace.model.target.TraceObject; import ghidra.trace.model.target.TraceObject;
@ -49,7 +50,7 @@ import ghidra.util.NotOwnerException;
public class DebuggerCoordinates { public class DebuggerCoordinates {
public static final DebuggerCoordinates NOWHERE = 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_LOC = "TraceProjLoc";
private static final String KEY_TRACE_PROJ_NAME = "TraceProjName"; private static final String KEY_TRACE_PROJ_NAME = "TraceProjName";
@ -65,6 +66,9 @@ public class DebuggerCoordinates {
if (!Objects.equals(a.trace, b.trace)) { if (!Objects.equals(a.trace, b.trace)) {
return false; return false;
} }
if (!Objects.equals(a.platform, b.platform)) {
return false;
}
if (!Objects.equals(a.thread, b.thread)) { if (!Objects.equals(a.thread, b.thread)) {
return false; return false;
} }
@ -82,6 +86,7 @@ public class DebuggerCoordinates {
} }
private final Trace trace; private final Trace trace;
private final TracePlatform platform;
private final TraceRecorder recorder; private final TraceRecorder recorder;
private final TraceThread thread; private final TraceThread thread;
private final TraceProgramView view; private final TraceProgramView view;
@ -94,9 +99,11 @@ public class DebuggerCoordinates {
private Long viewSnap; private Long viewSnap;
private DefaultTraceTimeViewport viewport; private DefaultTraceTimeViewport viewport;
DebuggerCoordinates(Trace trace, TraceRecorder recorder, TraceThread thread, DebuggerCoordinates(Trace trace, TracePlatform platform, TraceRecorder recorder,
TraceProgramView view, TraceSchedule time, Integer frame, TraceObject object) { TraceThread thread, TraceProgramView view, TraceSchedule time, Integer frame,
TraceObject object) {
this.trace = trace; this.trace = trace;
this.platform = platform;
this.recorder = recorder; this.recorder = recorder;
this.thread = thread; this.thread = thread;
this.view = view; this.view = view;
@ -151,6 +158,10 @@ public class DebuggerCoordinates {
return hash; return hash;
} }
private static TracePlatform resolvePlatform(Trace trace) {
return trace.getPlatformManager().getHostPlatform();
}
private static TraceThread resolveThread(Trace trace, TraceSchedule time) { private static TraceThread resolveThread(Trace trace, TraceSchedule time) {
long snap = time.getSnap(); long snap = time.getSnap();
return trace.getThreadManager() return trace.getThreadManager()
@ -186,13 +197,14 @@ public class DebuggerCoordinates {
return this; return this;
} }
if (trace == null) { if (trace == null) {
TracePlatform newPlatform = resolvePlatform(newTrace);
TraceThread newThread = resolveThread(newTrace); TraceThread newThread = resolveThread(newTrace);
TraceProgramView newView = resolveView(newTrace); TraceProgramView newView = resolveView(newTrace);
TraceSchedule newTime = null; // Allow later resolution TraceSchedule newTime = null; // Allow later resolution
Integer newFrame = resolveFrame(newThread, newTime); Integer newFrame = resolveFrame(newThread, newTime);
TraceObject newObject = resolveObject(newTrace); TraceObject newObject = resolveObject(newTrace);
return new DebuggerCoordinates(newTrace, null, newThread, newView, newTime, newFrame, return new DebuggerCoordinates(newTrace, newPlatform, null, newThread, newView, newTime,
newObject); newFrame, newObject);
} }
throw new IllegalArgumentException("Cannot change trace"); throw new IllegalArgumentException("Cannot change trace");
} }
@ -241,24 +253,54 @@ public class DebuggerCoordinates {
return resolveObject(recorder.getTrace(), recorder.getFocus()); 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) { public DebuggerCoordinates recorder(TraceRecorder newRecorder) {
if (recorder == newRecorder) { if (recorder == newRecorder) {
return this; return this;
} }
if (newRecorder == null) { 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) { if (newRecorder != null && trace != null && newRecorder.getTrace() != trace) {
throw new IllegalArgumentException("Cannot change trace"); throw new IllegalArgumentException("Cannot change trace");
} }
Trace newTrace = trace != null ? trace : newRecorder.getTrace(); Trace newTrace = trace != null ? trace : newRecorder.getTrace();
TracePlatform newPlatform = platform != null ? platform : resolvePlatform(newTrace);
TraceSchedule newTime = time != null ? time : TraceSchedule.snap(newRecorder.getSnap()); TraceSchedule newTime = time != null ? time : TraceSchedule.snap(newRecorder.getSnap());
TraceThread newThread = thread != null ? thread : resolveThread(newRecorder, newTime); TraceThread newThread = thread != null ? thread : resolveThread(newRecorder, newTime);
TraceProgramView newView = view != null ? view : resolveView(newTrace, newTime); TraceProgramView newView = view != null ? view : resolveView(newTrace, newTime);
Integer newFrame = frame != null ? frame : resolveFrame(newRecorder, newThread, newTime); Integer newFrame = frame != null ? frame : resolveFrame(newRecorder, newThread, newTime);
TraceObject newObject = object != null ? object : resolveObject(newRecorder, newTime); TraceObject newObject = object != null ? object : resolveObject(newRecorder, newTime);
return new DebuggerCoordinates(newTrace, newRecorder, newThread, newView, newTime, newFrame, return new DebuggerCoordinates(newTrace, newPlatform, newRecorder, newThread, newView,
newObject); newTime, newFrame, newObject);
} }
public DebuggerCoordinates reFindThread() { public DebuggerCoordinates reFindThread() {
@ -314,6 +356,7 @@ public class DebuggerCoordinates {
newThread = resolveThread(recorder, getTime()); newThread = resolveThread(recorder, getTime());
} }
Trace newTrace = trace != null ? trace : newThread.getTrace(); Trace newTrace = trace != null ? trace : newThread.getTrace();
TracePlatform newPlatform = platform != null ? platform : resolvePlatform(newTrace);
TraceSchedule newTime = time != null ? time : resolveTime(view); TraceSchedule newTime = time != null ? time : resolveTime(view);
TraceProgramView newView = view != null ? view : resolveView(newTrace, newTime); TraceProgramView newView = view != null ? view : resolveView(newTrace, newTime);
// Yes, override frame with 0 on thread changes, unless target says otherwise // 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 ancestor = resolveObject(newThread, newFrame, newTime);
TraceObject newObject = TraceObject newObject =
object != null && isAncestor(ancestor, object, newTime) ? object : ancestor; object != null && isAncestor(ancestor, object, newTime) ? object : ancestor;
return new DebuggerCoordinates(newTrace, recorder, newThread, newView, newTime, newFrame, return new DebuggerCoordinates(newTrace, newPlatform, recorder, newThread, newView, newTime,
newObject); newFrame, newObject);
} }
/** /**
@ -348,8 +391,8 @@ public class DebuggerCoordinates {
TraceObject ancestor = resolveObject(newThread, newFrame, newTime); TraceObject ancestor = resolveObject(newThread, newFrame, newTime);
TraceObject newObject = TraceObject newObject =
object != null && isAncestor(ancestor, object, newTime) ? object : ancestor; object != null && isAncestor(ancestor, object, newTime) ? object : ancestor;
return new DebuggerCoordinates(trace, recorder, newThread, view, newTime, newFrame, return new DebuggerCoordinates(trace, platform, recorder, newThread, view, newTime,
newObject); newFrame, newObject);
} }
public DebuggerCoordinates frame(int newFrame) { public DebuggerCoordinates frame(int newFrame) {
@ -362,11 +405,13 @@ public class DebuggerCoordinates {
TraceObject ancestor = resolveObject(thread, newFrame, getTime()); TraceObject ancestor = resolveObject(thread, newFrame, getTime());
TraceObject newObject = TraceObject newObject =
object != null && isAncestor(ancestor, object, getTime()) ? object : ancestor; 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) { 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) { private static TraceSchedule resolveTime(TraceProgramView view) {
@ -430,7 +475,7 @@ public class DebuggerCoordinates {
} }
else { else {
if (newObject == null) { if (newObject == null) {
return new DebuggerCoordinates(trace, recorder, thread, view, time, frame, return new DebuggerCoordinates(trace, platform, recorder, thread, view, time, frame,
newObject); newObject);
} }
if (newObject.getTrace() != trace) { if (newObject.getTrace() != trace) {
@ -438,11 +483,12 @@ public class DebuggerCoordinates {
} }
newTrace = trace; newTrace = trace;
} }
TracePlatform newPlatform = resolvePlatform(newTrace);
TraceThread newThread = resolveThread(newObject); TraceThread newThread = resolveThread(newObject);
Integer newFrame = resolveFrame(newObject); Integer newFrame = resolveFrame(newObject);
return new DebuggerCoordinates(newTrace, recorder, newThread, view, time, newFrame, return new DebuggerCoordinates(newTrace, newPlatform, recorder, newThread, view, time,
newObject); newFrame, newObject);
} }
protected static TraceThread resolveThread(TraceRecorder recorder, TargetObject targetObject) { protected static TraceThread resolveThread(TraceRecorder recorder, TargetObject targetObject) {
@ -463,7 +509,8 @@ public class DebuggerCoordinates {
} }
TraceThread newThread = resolveThread(recorder, targetObject); TraceThread newThread = resolveThread(recorder, targetObject);
Integer newFrame = resolveFrame(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) { public DebuggerCoordinates object(TargetObject newObject) {
@ -474,6 +521,10 @@ public class DebuggerCoordinates {
return trace; return trace;
} }
public TracePlatform getPlatform() {
return platform;
}
public TraceRecorder getRecorder() { public TraceRecorder getRecorder() {
return recorder; return recorder;
} }

View file

@ -31,7 +31,7 @@ import ghidra.pcode.utils.Utils;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace; import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.lang.Language; import ghidra.program.model.lang.Language;
import ghidra.trace.model.program.TraceProgramView; import ghidra.trace.model.guest.TracePlatform;
public abstract class DebuggerGoToTrait { public abstract class DebuggerGoToTrait {
protected DockingAction action; protected DockingAction action;
@ -68,19 +68,13 @@ public abstract class DebuggerGoToTrait {
} }
private void activatedGoTo(ActionContext context) { private void activatedGoTo(ActionContext context) {
TraceProgramView view = current.getView(); TracePlatform platform = current.getPlatform();
if (view == null) { goToDialog.show((SleighLanguage) platform.getLanguage());
return;
}
Language language = view.getLanguage();
if (!(language instanceof SleighLanguage)) {
return;
}
goToDialog.show((SleighLanguage) language);
} }
public CompletableFuture<Boolean> goToSleigh(String spaceName, String expression) { public CompletableFuture<Boolean> goToSleigh(String spaceName, String expression) {
Language language = current.getView().getLanguage(); TracePlatform platform = current.getPlatform();
Language language = platform.getLanguage();
if (!(language instanceof SleighLanguage)) { if (!(language instanceof SleighLanguage)) {
throw new IllegalStateException("Current trace does not use Sleigh"); 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); throw new IllegalArgumentException("No such address space: " + spaceName);
} }
PcodeExpression expr = SleighProgramCompiler.compileExpression(slang, expression); PcodeExpression expr = SleighProgramCompiler.compileExpression(slang, expression);
return goToSleigh(space, expr); return goToSleigh(platform, space, expr);
} }
public CompletableFuture<Boolean> goToSleigh(AddressSpace space, PcodeExpression expression) { public CompletableFuture<Boolean> goToSleigh(TracePlatform platform, AddressSpace space,
PcodeExpression expression) {
PcodeExecutor<byte[]> executor = DebuggerPcodeUtils.executorForCoordinates(tool, current); PcodeExecutor<byte[]> executor = DebuggerPcodeUtils.executorForCoordinates(tool, current);
CompletableFuture<byte[]> result = CompletableFuture<byte[]> result =
CompletableFuture.supplyAsync(() -> expression.evaluate(executor)); CompletableFuture.supplyAsync(() -> expression.evaluate(executor));
return result.thenApplyAsync(offset -> { return result.thenApplyAsync(offset -> {
Address address = space.getAddress( Address address = space.getAddress(
Utils.bytesToLong(offset, offset.length, expression.getLanguage().isBigEndian())); Utils.bytesToLong(offset, offset.length, expression.getLanguage().isBigEndian()));
return goToAddress(address); return goToAddress(platform.mapGuestToHost(address));
}, AsyncUtils.SWING_EXECUTOR); }, AsyncUtils.SWING_EXECUTOR);
} }
} }

View file

@ -209,7 +209,7 @@ public class DebuggerWatchesProvider extends ComponentProviderAdapter {
} }
protected static boolean sameCoordinates(DebuggerCoordinates a, DebuggerCoordinates b) { protected static boolean sameCoordinates(DebuggerCoordinates a, DebuggerCoordinates b) {
if (!Objects.equals(a.getTrace(), b.getTrace())) { if (!Objects.equals(a.getPlatform(), b.getPlatform())) {
return false; return false;
} }
if (!Objects.equals(a.getRecorder(), b.getRecorder())) { if (!Objects.equals(a.getRecorder(), b.getRecorder())) {
@ -543,7 +543,7 @@ public class DebuggerWatchesProvider extends ComponentProviderAdapter {
protected boolean selHasMemoryReads(DebuggerWatchActionContext ctx) { protected boolean selHasMemoryReads(DebuggerWatchActionContext ctx) {
for (WatchRow row : ctx.getWatchRows()) { for (WatchRow row : ctx.getWatchRows()) {
AddressSet set = row.getReads(); AddressSetView set = row.getReads();
if (set == null) { if (set == null) {
continue; continue;
} }
@ -634,7 +634,7 @@ public class DebuggerWatchesProvider extends ComponentProviderAdapter {
} }
AddressSet sel = new AddressSet(); AddressSet sel = new AddressSet();
for (WatchRow row : context.getWatchRows()) { for (WatchRow row : context.getWatchRows()) {
AddressSet reads = row.getReads(); AddressSetView reads = row.getReads();
if (reads != null) { if (reads != null) {
sel.add(reads); sel.add(reads);
} }
@ -858,7 +858,7 @@ public class DebuggerWatchesProvider extends ComponentProviderAdapter {
public synchronized void doCheckDepsAndReevaluate() { public synchronized void doCheckDepsAndReevaluate() {
for (WatchRow row : watchTableModel.getModelData()) { for (WatchRow row : watchTableModel.getModelData()) {
AddressSet reads = row.getReads(); AddressSetView reads = row.getReads();
if (reads == null || reads.intersects(changed)) { if (reads == null || reads.intersects(changed)) {
row.doTargetReads(); row.doTargetReads();
row.reevaluate(); row.reevaluate();

View file

@ -31,7 +31,6 @@ import ghidra.app.services.DebuggerStateEditingService.StateEditor;
import ghidra.docking.settings.Settings; import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsImpl; import ghidra.docking.settings.SettingsImpl;
import ghidra.framework.options.SaveState; import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.PluginTool;
import ghidra.pcode.exec.*; import ghidra.pcode.exec.*;
import ghidra.pcode.exec.trace.*; import ghidra.pcode.exec.trace.*;
import ghidra.pcode.utils.Utils; import ghidra.pcode.utils.Utils;
@ -76,7 +75,7 @@ public class WatchRow {
private TraceMemoryState state; private TraceMemoryState state;
private Address address; private Address address;
private Symbol symbol; private Symbol symbol;
private AddressSet reads; private AddressSetView reads;
private byte[] value; private byte[] value;
private byte[] prevValue; // Value at previous coordinates private byte[] prevValue; // Value at previous coordinates
private String valueString; private String valueString;
@ -140,12 +139,14 @@ public class WatchRow {
Pair<byte[], TraceMemoryState> valueWithState = compiled.evaluate(executorWithState); Pair<byte[], TraceMemoryState> valueWithState = compiled.evaluate(executorWithState);
Pair<byte[], Address> valueWithAddress = compiled.evaluate(executorWithAddress); Pair<byte[], Address> valueWithAddress = compiled.evaluate(executorWithAddress);
TracePlatform platform = provider.current.getPlatform();
value = valueWithState.getLeft(); value = valueWithState.getLeft();
error = null; error = null;
state = valueWithState.getRight(); state = valueWithState.getRight();
address = valueWithAddress.getRight(); // TODO: Optional column for guest address?
address = platform.mapGuestToHost(valueWithAddress.getRight());
symbol = computeSymbol(); symbol = computeSymbol();
reads = executorWithAddress.getReads(); reads = platform.mapGuestToHost(executorWithAddress.getReads());
valueObj = parseAsDataTypeObj(); valueObj = parseAsDataTypeObj();
valueString = parseAsDataTypeStr(); valueString = parseAsDataTypeStr();
@ -245,26 +246,24 @@ public class WatchRow {
* the computation. The resulting pair gives the value and its address. To get the addresses * the computation. The resulting pair gives the value and its address. To get the addresses
* involved, invoke {@link ReadDepsPcodeExecutor#getReads()} after evaluation. * involved, invoke {@link ReadDepsPcodeExecutor#getReads()} after evaluation.
* *
* @param tool the plugin tool
* @param coordinates the coordinates providing context for the evaluation * @param coordinates the coordinates providing context for the evaluation
* @return an executor for evaluating the watch * @return an executor for evaluating the watch
*/ */
protected static ReadDepsPcodeExecutor buildAddressDepsExecutor(PluginTool tool, protected static ReadDepsPcodeExecutor buildAddressDepsExecutor(
DebuggerCoordinates coordinates) { DebuggerCoordinates coordinates) {
Trace trace = coordinates.getTrace(); TracePlatform platform = coordinates.getPlatform();
TracePlatform platform = DebuggerPcodeUtils.getCurrentPlatform(tool, coordinates);
ReadDepsTraceBytesPcodeExecutorStatePiece piece = ReadDepsTraceBytesPcodeExecutorStatePiece piece =
new ReadDepsTraceBytesPcodeExecutorStatePiece(platform, coordinates.getViewSnap(), new ReadDepsTraceBytesPcodeExecutorStatePiece(platform, coordinates.getViewSnap(),
coordinates.getThread(), coordinates.getFrame()); coordinates.getThread(), coordinates.getFrame());
Language language = trace.getBaseLanguage(); Language language = platform.getLanguage();
if (!(language instanceof SleighLanguage)) { if (!(language instanceof SleighLanguage slang)) {
throw new IllegalArgumentException("Watch expressions require a SLEIGH language"); throw new IllegalArgumentException("Watch expressions require a Sleigh language");
} }
PcodeExecutorState<Pair<byte[], Address>> paired = new DefaultPcodeExecutorState<>(piece) PcodeExecutorState<Pair<byte[], Address>> paired = new DefaultPcodeExecutorState<>(piece)
.paired(new AddressOfPcodeExecutorStatePiece(language)); .paired(new AddressOfPcodeExecutorStatePiece(language));
PairedPcodeArithmetic<byte[], Address> arithmetic = new PairedPcodeArithmetic<>( PairedPcodeArithmetic<byte[], Address> arithmetic = new PairedPcodeArithmetic<>(
BytesPcodeArithmetic.forLanguage(language), AddressOfPcodeArithmetic.INSTANCE); 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) { public void setCoordinates(DebuggerCoordinates coordinates) {
@ -292,7 +291,7 @@ public class WatchRow {
} }
executorWithState = TraceSleighUtils.buildByteWithStateExecutor(trace, executorWithState = TraceSleighUtils.buildByteWithStateExecutor(trace,
coordinates.getViewSnap(), coordinates.getThread(), coordinates.getFrame()); coordinates.getViewSnap(), coordinates.getThread(), coordinates.getFrame());
executorWithAddress = buildAddressDepsExecutor(provider.getTool(), coordinates); executorWithAddress = buildAddressDepsExecutor(coordinates);
} }
public void setExpression(String expression) { public void setExpression(String expression) {
@ -423,7 +422,12 @@ public class WatchRow {
return "{ " + NumericUtilities.convertBytesToString(value, " ") + " }"; 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; return reads;
} }

View file

@ -43,7 +43,6 @@ import ghidra.async.AsyncLazyMap;
import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.annotation.AutoServiceConsumed; import ghidra.framework.plugintool.annotation.AutoServiceConsumed;
import ghidra.framework.plugintool.util.PluginStatus; import ghidra.framework.plugintool.util.PluginStatus;
import ghidra.pcode.exec.DebuggerPcodeUtils;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.program.util.ProgramLocation; 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? * TODO: object and/or platform should somehow be incorporated into the key, the schedule?
* something? * something?
*/ */
TracePlatform platform = DebuggerPcodeUtils.getCurrentPlatform(platformService, DebuggerCoordinates current = traceManager.resolveTrace(trace);
traceManager.getCurrentFor(trace).trace(trace)); TracePlatform platform = current.getPlatform();
TraceSchedule time = key.time; TraceSchedule time = key.time;
CachedEmulator ce; CachedEmulator ce;

View file

@ -31,6 +31,7 @@ import ghidra.app.plugin.core.debug.DebuggerCoordinates;
import ghidra.app.plugin.core.debug.DebuggerPluginPackage; import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
import ghidra.app.plugin.core.debug.event.*; import ghidra.app.plugin.core.debug.event.*;
import ghidra.app.plugin.core.debug.gui.DebuggerResources.*; import ghidra.app.plugin.core.debug.gui.DebuggerResources.*;
import ghidra.app.plugin.core.debug.mapping.DebuggerPlatformMapper;
import ghidra.app.services.*; import ghidra.app.services.*;
import ghidra.async.*; import ghidra.async.*;
import ghidra.async.AsyncConfigFieldCodec.BooleanAsyncConfigFieldCodec; import ghidra.async.AsyncConfigFieldCodec.BooleanAsyncConfigFieldCodec;
@ -48,6 +49,7 @@ import ghidra.lifecycle.Internal;
import ghidra.trace.model.Trace; import ghidra.trace.model.Trace;
import ghidra.trace.model.Trace.TraceThreadChangeType; import ghidra.trace.model.Trace.TraceThreadChangeType;
import ghidra.trace.model.TraceDomainObjectListener; import ghidra.trace.model.TraceDomainObjectListener;
import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.program.TraceProgramView; import ghidra.trace.model.program.TraceProgramView;
import ghidra.trace.model.program.TraceVariableSnapProgramView; import ghidra.trace.model.program.TraceVariableSnapProgramView;
import ghidra.trace.model.stack.TraceStackFrame; import ghidra.trace.model.stack.TraceStackFrame;
@ -75,6 +77,7 @@ import ghidra.util.task.*;
TraceClosedPluginEvent.class, TraceClosedPluginEvent.class,
ModelObjectFocusedPluginEvent.class, ModelObjectFocusedPluginEvent.class,
TraceRecorderAdvancedPluginEvent.class, TraceRecorderAdvancedPluginEvent.class,
DebuggerPlatformPluginEvent.class,
}, },
servicesRequired = {}, servicesRequired = {},
servicesProvided = { servicesProvided = {
@ -504,6 +507,23 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
activateSnap(snap); 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) { protected TraceRecorder computeRecorder(Trace trace) {
if (modelService == null) { if (modelService == null) {
return null; return null;
@ -531,25 +551,24 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
@Override @Override
public void processEvent(PluginEvent event) { public void processEvent(PluginEvent event) {
super.processEvent(event); super.processEvent(event);
if (event instanceof TraceActivatedPluginEvent) { if (event instanceof TraceActivatedPluginEvent ev) {
TraceActivatedPluginEvent ev = (TraceActivatedPluginEvent) event;
synchronized (listenersByTrace) { synchronized (listenersByTrace) {
doSetCurrent(ev.getActiveCoordinates()); doSetCurrent(ev.getActiveCoordinates());
} }
} }
else if (event instanceof TraceClosedPluginEvent) { else if (event instanceof TraceClosedPluginEvent ev) {
TraceClosedPluginEvent ev = (TraceClosedPluginEvent) event;
doTraceClosed(ev.getTrace()); doTraceClosed(ev.getTrace());
} }
else if (event instanceof ModelObjectFocusedPluginEvent) { else if (event instanceof ModelObjectFocusedPluginEvent ev) {
ModelObjectFocusedPluginEvent ev = (ModelObjectFocusedPluginEvent) event;
doModelObjectFocused(ev.getFocus(), true); doModelObjectFocused(ev.getFocus(), true);
} }
else if (event instanceof TraceRecorderAdvancedPluginEvent) { else if (event instanceof TraceRecorderAdvancedPluginEvent ev) {
TraceRecorderAdvancedPluginEvent ev = (TraceRecorderAdvancedPluginEvent) event; // TimedMsg.debug(this, "Processing trace-advanced event");
TimedMsg.debug(this, "Processing trace-advanced event");
doTraceRecorderAdvanced(ev.getRecorder(), ev.getSnap()); doTraceRecorderAdvanced(ev.getRecorder(), ev.getSnap());
} }
else if (event instanceof DebuggerPlatformPluginEvent ev) {
doPlatformMapperSelected(ev.getTrace(), ev.getMapper());
}
} }
@Override @Override
@ -576,6 +595,11 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
return current.getTrace(); return current.getTrace();
} }
@Override
public TracePlatform getCurrentPlatform() {
return current.getPlatform();
}
@Override @Override
public TraceProgramView getCurrentView() { public TraceProgramView getCurrentView() {
return current.getView(); return current.getView();
@ -1006,6 +1030,12 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
return getCurrentFor(trace).trace(trace); return getCurrentFor(trace).trace(trace);
} }
@Override
public DebuggerCoordinates resolvePlatform(TracePlatform platform) {
Trace trace = platform == null ? null : platform.getTrace();
return getCurrentFor(trace).platform(platform);
}
@Override @Override
public DebuggerCoordinates resolveThread(TraceThread thread) { public DebuggerCoordinates resolveThread(TraceThread thread) {
Trace trace = thread == null ? null : thread.getTrace(); Trace trace = thread == null ? null : thread.getTrace();

View file

@ -25,6 +25,7 @@ import ghidra.framework.model.DomainFile;
import ghidra.framework.plugintool.ServiceInfo; import ghidra.framework.plugintool.ServiceInfo;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.trace.model.Trace; import ghidra.trace.model.Trace;
import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.program.TraceProgramView; import ghidra.trace.model.program.TraceProgramView;
import ghidra.trace.model.target.TraceObject; import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.thread.TraceThread; import ghidra.trace.model.thread.TraceThread;
@ -89,6 +90,13 @@ public interface DebuggerTraceManagerService {
*/ */
Trace getCurrentTrace(); Trace getCurrentTrace();
/**
* Get the active platform
*
* @return the active platform, or null
*/
TracePlatform getCurrentPlatform();
/** /**
* Get the active view * Get the active view
* *
@ -263,6 +271,24 @@ public interface DebuggerTraceManagerService {
activate(resolveTrace(trace)); 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" * Resolve coordinates for the given thread using the manager's "best judgment"
* *

View file

@ -15,15 +15,10 @@
*/ */
package ghidra.pcode.exec; package ghidra.pcode.exec;
import java.util.Objects;
import ghidra.app.plugin.core.debug.DebuggerCoordinates; 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.*;
import ghidra.app.plugin.core.debug.service.emulation.data.DefaultPcodeDebuggerAccess; import ghidra.app.plugin.core.debug.service.emulation.data.DefaultPcodeDebuggerAccess;
import ghidra.app.plugin.processors.sleigh.SleighLanguage; import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.app.services.DebuggerPlatformService;
import ghidra.app.services.DebuggerTraceManagerService;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.pcode.emu.ThreadPcodeExecutorState; import ghidra.pcode.emu.ThreadPcodeExecutorState;
import ghidra.program.model.lang.Language; import ghidra.program.model.lang.Language;
@ -36,45 +31,6 @@ import ghidra.trace.model.guest.TracePlatform;
public enum DebuggerPcodeUtils { public enum DebuggerPcodeUtils {
; ;
/**
* Get the current platform
*
* <p>
* 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
*
* <p>
* 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 * Get a p-code executor state for the given coordinates
* *
@ -93,7 +49,7 @@ public enum DebuggerPcodeUtils {
if (trace == null) { if (trace == null) {
throw new IllegalArgumentException("Coordinates have no trace"); throw new IllegalArgumentException("Coordinates have no trace");
} }
TracePlatform platform = getCurrentPlatform(tool, coordinates); TracePlatform platform = coordinates.getPlatform();
Language language = platform.getLanguage(); Language language = platform.getLanguage();
if (!(language instanceof SleighLanguage)) { if (!(language instanceof SleighLanguage)) {
throw new IllegalArgumentException( throw new IllegalArgumentException(

View file

@ -18,6 +18,7 @@ package ghidra.app.plugin.core.debug.service.emulation;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.math.BigInteger; import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import org.junit.Before; import org.junit.Before;
@ -28,18 +29,23 @@ import com.google.common.collect.Range;
import generic.Unique; import generic.Unique;
import generic.test.category.NightlyCategory; import generic.test.category.NightlyCategory;
import ghidra.app.plugin.assembler.Assembler; import ghidra.app.plugin.assembler.*;
import ghidra.app.plugin.assembler.Assemblers;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin; import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest; 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.app.services.DebuggerStaticMappingService;
import ghidra.pcode.utils.Utils;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace; import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.lang.*; import ghidra.program.model.lang.*;
import ghidra.program.model.mem.Memory; import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryBlock; import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.util.ProgramLocation; 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.TraceMemoryManager;
import ghidra.trace.model.memory.TraceMemorySpace; import ghidra.trace.model.memory.TraceMemorySpace;
import ghidra.trace.model.thread.TraceThread; import ghidra.trace.model.thread.TraceThread;
@ -278,4 +284,55 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerGU
assertEquals("deadbeefcafebabe", assertEquals("deadbeefcafebabe",
regs.getViewValue(scratch, tb.reg("RAX")).getUnsignedValue().toString(16)); 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));
}
} }

View file

@ -266,7 +266,8 @@ public class DBTraceMemoryManager extends AbstractDBTraceSpaceBasedManager<DBTra
@Override @Override
public Entry<Long, TraceMemoryState> getViewState(long snap, Address address) { public Entry<Long, TraceMemoryState> 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 @Override

View file

@ -225,7 +225,8 @@ public class DefaultPcodeThread<T> implements PcodeThread<T> {
this.library = createUseropLibrary(); this.library = createUseropLibrary();
this.executor = createExecutor(); this.executor = createExecutor();
this.pc = language.getProgramCounter(); this.pc =
Objects.requireNonNull(language.getProgramCounter(), "Language has no program counter");
this.contextreg = language.getContextBaseRegister(); this.contextreg = language.getContextBaseRegister();
if (contextreg != Register.NO_CONTEXT) { if (contextreg != Register.NO_CONTEXT) {