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.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;
}

View file

@ -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<Boolean> 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<Boolean> goToSleigh(AddressSpace space, PcodeExpression expression) {
public CompletableFuture<Boolean> goToSleigh(TracePlatform platform, AddressSpace space,
PcodeExpression expression) {
PcodeExecutor<byte[]> executor = DebuggerPcodeUtils.executorForCoordinates(tool, current);
CompletableFuture<byte[]> 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);
}
}

View file

@ -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();

View file

@ -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<byte[], TraceMemoryState> valueWithState = compiled.evaluate(executorWithState);
Pair<byte[], Address> 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<Pair<byte[], Address>> paired = new DefaultPcodeExecutorState<>(piece)
.paired(new AddressOfPcodeExecutorStatePiece(language));
PairedPcodeArithmetic<byte[], Address> 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;
}

View file

@ -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;

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.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();

View file

@ -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"
*

View file

@ -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
*
* <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
*
@ -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(

View file

@ -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));
}
}

View file

@ -266,7 +266,8 @@ public class DBTraceMemoryManager extends AbstractDBTraceSpaceBasedManager<DBTra
@Override
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

View file

@ -225,7 +225,8 @@ public class DefaultPcodeThread<T> implements PcodeThread<T> {
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) {