mirror of
https://github.com/NationalSecurityAgency/ghidra
synced 2024-10-30 02:29:46 +00:00
GP-2522: Add platform to DebuggerCoordinates
This commit is contained in:
parent
89b0f92e50
commit
e0730a31b7
11 changed files with 232 additions and 112 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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"
|
||||
*
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue