GP-2062: Add Skip Instruction button for emulator

This commit is contained in:
Dan 2022-06-16 09:08:17 -04:00
parent 00dbd26511
commit 4736a3c924
20 changed files with 961 additions and 614 deletions

View file

@ -125,6 +125,18 @@
the next tick, using emulation. Note that emulation does not affect the target. Furthermore,
emulation may halt early if it encounters certain instructions or causes an exception.</P>
<H3><A name="emu_trace_skip_tick_forward"></A><IMG alt="" src="images/skipover.png">Emulate
Trace Skip Tick Forward</H3>
<P>This action is available when a thread is selected. It steps the current thread forward by
skipping the next instruction, using emulation. Note that emulation does not affect the target.
Furthermore, emulation may halt early if it encounters certain instructions or causes an
exception. This action may be used skip subroutines; <B>however</B>, the stack may require
additional patching, e.g., to clean up stack parameters, depending on the calling convention.
This action <EM>does not</EM> perform those patches automatically. It only advances the program
counter. You may use <A href="#goto_time">Go To Time</A> to append the require stack patch,
e.g., <CODE>t0-{RSP=RSP+8}</CODE>.</P>
<H3><A name="seek_trace_present"></A><IMG alt="" src="images/continue.png">Seek Trace to
Present</H3>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 B

View file

@ -87,6 +87,7 @@ public interface DebuggerResources {
ImageIcon ICON_STEP_INTO = ResourceManager.loadImage("images/stepinto.png");
ImageIcon ICON_STEP_OVER = ResourceManager.loadImage("images/stepover.png");
ImageIcon ICON_SKIP_OVER = ResourceManager.loadImage("images/skipover.png");
ImageIcon ICON_STEP_FINISH = ResourceManager.loadImage("images/stepout.png");
ImageIcon ICON_STEP_BACK = ResourceManager.loadImage("images/stepback.png");
// TODO: Draw new icons?
@ -1641,81 +1642,12 @@ public interface DebuggerResources {
}
}
interface StepSnapForwardAction {
String NAME = "Step Trace Snap Forward";
String DESCRIPTION = "Navigate the recording forward one snap";
Icon ICON = ICON_SNAP_FORWARD;
String GROUP = GROUP_CONTROL;
String HELP_ANCHOR = "step_trace_snap_forward";
static ActionBuilder builder(Plugin owner) {
String ownerName = owner.getName();
return new ActionBuilder(NAME, ownerName)
.description(DESCRIPTION)
.toolBarIcon(ICON)
.toolBarGroup(GROUP, "4")
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
}
}
abstract class AbstractStepSnapForwardAction extends DockingAction {
public static final String NAME = StepSnapForwardAction.NAME;
public static final Icon ICON = StepSnapForwardAction.ICON;
public static final String HELP_ANCHOR = StepSnapForwardAction.HELP_ANCHOR;
public AbstractStepSnapForwardAction(Plugin owner) {
super(NAME, owner.getName());
setDescription(StepSnapForwardAction.DESCRIPTION);
setHelpLocation(new HelpLocation(owner.getName(), HELP_ANCHOR));
}
}
abstract class AbstractEmulateTickForwardAction extends DockingAction {
public static final String NAME = "Emulate Trace Tick Forward";
public static final Icon ICON = ICON_STEP_INTO;
public static final String HELP_ANCHOR = "emu_trace_tick_forward";
public AbstractEmulateTickForwardAction(Plugin owner) {
super(NAME, owner.getName());
setDescription("Emulate the recording forward one tick");
setHelpLocation(new HelpLocation(owner.getName(), HELP_ANCHOR));
}
}
interface EmulatePcodeForwardAction {
String NAME = "Emulate Trace p-code Forward";
String DESCRIPTION = "Navigate the recording forward one p-code tick";
Icon ICON = ICON_STEP_INTO;
String GROUP = GROUP_CONTROL;
String HELP_ANCHOR = "emu_trace_pcode_forward";
static ActionBuilder builder(Plugin owner) {
String ownerName = owner.getName();
return new ActionBuilder(NAME, ownerName)
.description(DESCRIPTION)
.toolBarIcon(ICON)
.toolBarGroup(GROUP)
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
}
}
abstract class AbstractEmulateTickBackwardAction extends DockingAction {
public static final String NAME = "Emulate Trace Tick Backward";
public static final Icon ICON = ICON_STEP_BACK;
public static final String HELP_ANCHOR = "emu_trace_tick_backward";
public AbstractEmulateTickBackwardAction(Plugin owner) {
super(NAME, owner.getName());
setDescription("Emulate the recording backward one tick");
setHelpLocation(new HelpLocation(owner.getName(), HELP_ANCHOR));
}
}
interface StepSnapBackwardAction {
String NAME = "Step Trace Snap Backward";
String DESCRIPTION = "Navigate the recording backward one snap";
Icon ICON = ICON_SNAP_BACKWARD;
String GROUP = GROUP_CONTROL;
String ORDER = "1";
String HELP_ANCHOR = "step_trace_snap_backward";
static ActionBuilder builder(Plugin owner) {
@ -1723,20 +1655,80 @@ public interface DebuggerResources {
return new ActionBuilder(NAME, ownerName)
.description(DESCRIPTION)
.toolBarIcon(ICON)
.toolBarGroup(GROUP, "1")
.toolBarGroup(GROUP, ORDER)
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
}
}
abstract class AbstractStepSnapBackwardAction extends DockingAction {
public static final String NAME = StepSnapBackwardAction.NAME;
public static final Icon ICON = StepSnapBackwardAction.ICON;;
public static final String HELP_ANCHOR = StepSnapBackwardAction.HELP_ANCHOR;
interface StepSnapForwardAction {
String NAME = "Step Trace Snap Forward";
String DESCRIPTION = "Navigate the recording forward one snap";
Icon ICON = ICON_SNAP_FORWARD;
String GROUP = GROUP_CONTROL;
String ORDER = "5";
String HELP_ANCHOR = "step_trace_snap_forward";
public AbstractStepSnapBackwardAction(Plugin owner) {
super(NAME, owner.getName());
setDescription(StepSnapBackwardAction.DESCRIPTION);
setHelpLocation(new HelpLocation(owner.getName(), HELP_ANCHOR));
static ActionBuilder builder(Plugin owner) {
String ownerName = owner.getName();
return new ActionBuilder(NAME, ownerName)
.description(DESCRIPTION)
.toolBarIcon(ICON)
.toolBarGroup(GROUP, ORDER)
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
}
}
interface EmulateTickBackwardAction {
String NAME = "Emulate Trace Tick Backward";
String DESCRIPTION = "Emulate the recording backward one tick";
Icon ICON = ICON_STEP_BACK;
String GROUP = GROUP_CONTROL;
String ORDER = "2";
String HELP_ANCHOR = "emu_trace_tick_backward";
static ActionBuilder builder(Plugin owner) {
String ownerName = owner.getName();
return new ActionBuilder(NAME, ownerName)
.description(DESCRIPTION)
.toolBarIcon(ICON)
.toolBarGroup(GROUP, ORDER)
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
}
}
interface EmulateTickForwardAction {
String NAME = "Emulate Trace Tick Forward";
String DESCRIPTION = "Emulate the recording forward one instruction";
Icon ICON = ICON_STEP_INTO;
String GROUP = GROUP_CONTROL;
String ORDER = "3";
String HELP_ANCHOR = "emu_trace_tick_forward";
static ActionBuilder builder(Plugin owner) {
String ownerName = owner.getName();
return new ActionBuilder(NAME, ownerName)
.description(DESCRIPTION)
.toolBarIcon(ICON)
.toolBarGroup(GROUP, ORDER)
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
}
}
interface EmulateSkipTickForwardAction {
String NAME = "Emulate Trace Skip Tick Forward";
String DESCRIPTION = "Emulate the recording forward by skipping one instruction";
Icon ICON = ICON_SKIP_OVER;
String GROUP = GROUP_CONTROL;
String ORDER = "4";
String HELP_ANCHOR = "emu_trace_skip_tick_forward";
static ActionBuilder builder(Plugin owner) {
String ownerName = owner.getName();
return new ActionBuilder(NAME, ownerName)
.description(DESCRIPTION)
.toolBarIcon(ICON)
.toolBarGroup(GROUP, ORDER)
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
}
}
@ -1745,8 +1737,45 @@ public interface DebuggerResources {
String DESCRIPTION = "Navigate the recording backward one p-code tick";
Icon ICON = ICON_STEP_BACK;
String GROUP = GROUP_CONTROL;
String ORDER = "2";
String HELP_ANCHOR = "emu_trace_pcode_backward";
static ActionBuilder builder(Plugin owner) {
String ownerName = owner.getName();
return new ActionBuilder(NAME, ownerName)
.description(DESCRIPTION)
.toolBarIcon(ICON)
.toolBarGroup(GROUP, ORDER)
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
}
}
interface EmulatePcodeForwardAction {
String NAME = "Emulate Trace p-code Forward";
String DESCRIPTION = "Emulate the recording forward one p-code tick";
Icon ICON = ICON_STEP_INTO;
String GROUP = GROUP_CONTROL;
String ORDER = "3";
String HELP_ANCHOR = "emu_trace_pcode_forward";
static ActionBuilder builder(Plugin owner) {
String ownerName = owner.getName();
return new ActionBuilder(NAME, ownerName)
.description(DESCRIPTION)
.toolBarIcon(ICON)
.toolBarGroup(GROUP, ORDER)
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
}
}
interface EmulateSkipPcodeForwardAction {
String NAME = "Emulate Trace Skip P-code Forward";
String DESCRIPTION = "Emulate the recording forward by skipping one p-code op";
Icon ICON = ICON_SKIP_OVER;
String GROUP = GROUP_CONTROL;
String ORDER = "4";
String HELP_ANCHOR = "emu_trace_skip_pcode_forward";
static ActionBuilder builder(Plugin owner) {
String ownerName = owner.getName();
return new ActionBuilder(NAME, ownerName)
@ -1757,15 +1786,20 @@ public interface DebuggerResources {
}
}
abstract class AbstractSeekTracePresentAction extends ToggleDockingAction {
public static final String NAME = "Seek Trace Present";
public static final Icon ICON = ICON_SEEK_PRESENT;
public static final String HELP_ANCHOR = "seek_trace_present";
interface SeekTracePresentAction {
String NAME = "Seek Trace Present";
String DESCRIPTION = "Track the tool to the latest snap";
Icon ICON = ICON_SEEK_PRESENT;
String GROUP = "zz";
String HELP_ANCHOR = "seek_trace_present";
public AbstractSeekTracePresentAction(Plugin owner) {
super(NAME, owner.getName());
setDescription("Track the tool to the latest snap");
setHelpLocation(new HelpLocation(owner.getName(), HELP_ANCHOR));
static ToggleActionBuilder builder(Plugin owner) {
String ownerName = owner.getName();
return new ToggleActionBuilder(NAME, ownerName)
.description(DESCRIPTION)
.toolBarIcon(ICON)
.toolBarGroup(GROUP)
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
}
}

View file

@ -87,172 +87,6 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter {
return true;
}
protected class StepSnapBackwardAction extends AbstractStepSnapBackwardAction {
public static final String GROUP = DebuggerResources.GROUP_CONTROL;
public StepSnapBackwardAction() {
super(plugin);
setToolBarData(new ToolBarData(ICON, GROUP, "1"));
addLocalAction(this);
setEnabled(false);
}
@Override
public void actionPerformed(ActionContext context) {
if (current.getTime().isSnapOnly()) {
traceManager.activateSnap(current.getSnap() - 1);
}
else {
traceManager.activateSnap(current.getSnap());
}
}
@Override
public boolean isEnabledForContext(ActionContext context) {
if (current.getTrace() == null) {
return false;
}
if (!current.getTime().isSnapOnly()) {
return true;
}
if (current.getSnap() <= 0) {
return false;
}
return true;
}
}
protected class EmulateTickBackwardAction extends AbstractEmulateTickBackwardAction {
public static final String GROUP = DebuggerResources.GROUP_CONTROL;
public EmulateTickBackwardAction() {
super(plugin);
setToolBarData(new ToolBarData(ICON, GROUP, "2"));
addLocalAction(this);
setEnabled(false);
}
@Override
public void actionPerformed(ActionContext context) {
if (current.getTrace() == null) {
return;
}
TraceSchedule time = current.getTime().steppedBackward(current.getTrace(), 1);
if (time == null) {
return;
}
traceManager.activateTime(time);
}
@Override
public boolean isEnabledForContext(ActionContext context) {
if (emulationService == null) {
return false;
}
if (current.getTrace() == null) {
return false;
}
if (current.getTime().steppedBackward(current.getTrace(), 1) == null) {
return false;
}
return true;
}
}
protected class EmulateTickForwardAction extends AbstractEmulateTickForwardAction {
public static final String GROUP = DebuggerResources.GROUP_CONTROL;
public EmulateTickForwardAction() {
super(plugin);
setToolBarData(new ToolBarData(ICON, GROUP, "3"));
addLocalAction(this);
setEnabled(false);
}
@Override
public void actionPerformed(ActionContext context) {
if (current.getThread() == null) {
return;
}
TraceSchedule time = current.getTime().steppedForward(current.getThread(), 1);
traceManager.activateTime(time);
}
@Override
public boolean isEnabledForContext(ActionContext context) {
if (emulationService == null) {
return false;
}
if (current.getThread() == null) {
return false;
}
return true;
}
}
protected class StepSnapForwardAction extends AbstractStepSnapForwardAction {
public static final String GROUP = DebuggerResources.GROUP_CONTROL;
public StepSnapForwardAction() {
super(plugin);
setToolBarData(new ToolBarData(ICON, GROUP, "4"));
addLocalAction(this);
setEnabled(false);
}
@Override
public void actionPerformed(ActionContext context) {
traceManager.activateSnap(current.getSnap() + 1);
}
@Override
public boolean isEnabledForContext(ActionContext context) {
Trace curTrace = current.getTrace();
if (curTrace == null) {
return false;
}
Long maxSnap = curTrace.getTimeManager().getMaxSnap();
if (maxSnap == null || current.getSnap() >= maxSnap) {
return false;
}
return true;
}
}
protected class SeekTracePresentAction extends AbstractSeekTracePresentAction
implements BooleanChangeAdapter {
public static final String GROUP = "zz";
public SeekTracePresentAction() {
super(plugin);
setToolBarData(new ToolBarData(ICON, GROUP));
addLocalAction(this);
setSelected(traceManager == null ? false : traceManager.isAutoActivatePresent());
traceManager.addAutoActivatePresentChangeListener(this);
}
@Override
public boolean isEnabledForContext(ActionContext context) {
return traceManager != null;
}
@Override
public void actionPerformed(ActionContext context) {
if (traceManager == null) {
return;
}
traceManager.setAutoActivatePresent(isSelected());
}
@Override
public void changed(Boolean value) {
if (isSelected() == value) {
return;
}
setSelected(value);
}
}
protected static class ThreadTableModel
extends RowWrappedEnumeratedColumnTableModel< //
ThreadTableColumns, ObjectKey, ThreadRow, TraceThread> {
@ -321,9 +155,9 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter {
private final DebuggerThreadsPlugin plugin;
// @AutoServiceConsumed by method
// @AutoServiceConsumed by method
private DebuggerModelService modelService;
@AutoServiceConsumed // NB, also by method
// @AutoServiceConsumed by method
private DebuggerTraceManagerService traceManager;
@AutoServiceConsumed // NB, also by method
private DebuggerEmulationService emulationService;
@ -337,6 +171,10 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter {
private final ThreadsListener threadsListener = new ThreadsListener();
private final CollectionChangeListener<TraceRecorder> recordersListener =
new RecordersChangeListener();
private final BooleanChangeAdapter activatePresentChangeListener =
this::changedAutoActivatePresent;
private final BooleanChangeAdapter synchronizeFocusChangeListener =
this::changedSynchronizeFocus;
/* package access for testing */
final RangeTableCellRenderer<Long> rangeRenderer = new RangeTableCellRenderer<>();
final RangeCursorTableHeaderRenderer<Long> headerRenderer =
@ -354,11 +192,12 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter {
private ActionContext myActionContext;
DockingAction actionSaveTrace;
StepSnapBackwardAction actionStepSnapBackward;
EmulateTickBackwardAction actionEmulateTickBackward;
EmulateTickForwardAction actionEmulateTickForward;
StepSnapForwardAction actionStepSnapForward;
SeekTracePresentAction actionSeekTracePresent;
DockingAction actionStepSnapBackward;
DockingAction actionEmulateTickBackward;
DockingAction actionEmulateTickForward;
DockingAction actionEmulateTickSkipForward;
DockingAction actionStepSnapForward;
ToggleDockingAction actionSeekTracePresent;
ToggleDockingAction actionSyncFocus;
DockingAction actionGoToTime;
@ -410,9 +249,21 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter {
@AutoServiceConsumed
public void setTraceManager(DebuggerTraceManagerService traceManager) {
if (traceManager != null && actionSeekTracePresent != null) {
actionSeekTracePresent.setSelected(traceManager.isAutoActivatePresent());
actionSyncFocus.setSelected(traceManager.isSynchronizeFocus());
if (this.traceManager != null) {
this.traceManager
.removeAutoActivatePresentChangeListener(activatePresentChangeListener);
this.traceManager.removeSynchronizeFocusChangeListener(synchronizeFocusChangeListener);
}
this.traceManager = traceManager;
if (traceManager != null) {
traceManager.addAutoActivatePresentChangeListener(activatePresentChangeListener);
traceManager.addSynchronizeFocusChangeListener(synchronizeFocusChangeListener);
if (actionSeekTracePresent != null) {
actionSeekTracePresent.setSelected(traceManager.isAutoActivatePresent());
}
if (actionSyncFocus != null) {
actionSyncFocus.setSelected(traceManager.isSynchronizeFocus());
}
}
contextChanged();
}
@ -633,11 +484,34 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter {
protected void createActions() {
// TODO: Make other actions use builder?
actionStepSnapBackward = new StepSnapBackwardAction();
actionEmulateTickBackward = new EmulateTickBackwardAction();
actionEmulateTickForward = new EmulateTickForwardAction();
actionStepSnapForward = new StepSnapForwardAction();
actionSeekTracePresent = new SeekTracePresentAction();
actionStepSnapBackward = StepSnapBackwardAction.builder(plugin)
.enabledWhen(this::isStepSnapBackwardEnabled)
.enabled(false)
.onAction(this::activatedStepSnapBackward)
.buildAndInstallLocal(this);
actionEmulateTickBackward = EmulateTickBackwardAction.builder(plugin)
.enabledWhen(this::isEmulateTickBackwardEnabled)
.onAction(this::activatedEmulateTickBackward)
.buildAndInstallLocal(this);
actionEmulateTickForward = EmulateTickForwardAction.builder(plugin)
.enabledWhen(this::isEmulateTickForwardEnabled)
.onAction(this::activatedEmulateTickForward)
.buildAndInstallLocal(this);
actionEmulateTickSkipForward = EmulateSkipTickForwardAction.builder(plugin)
.enabledWhen(this::isEmulateSkipTickForwardEnabled)
.onAction(this::activatedEmulateSkipTickForward)
.buildAndInstallLocal(this);
actionStepSnapForward = StepSnapForwardAction.builder(plugin)
.enabledWhen(this::isStepSnapForwardEnabled)
.enabled(false)
.onAction(this::activatedStepSnapForward)
.buildAndInstallLocal(this);
actionSeekTracePresent = SeekTracePresentAction.builder(plugin)
.enabledWhen(this::isSeekTracePresentEnabled)
.onAction(this::toggledSeekTracePresent)
.selected(traceManager == null ? false : traceManager.isAutoActivatePresent())
.buildAndInstallLocal(this);
actionSyncFocus = SynchronizeFocusAction.builder(plugin)
.selected(traceManager != null && traceManager.isSynchronizeFocus())
.enabledWhen(c -> traceManager != null)
@ -672,6 +546,129 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter {
.buildAndInstallLocal(this);
}
private boolean isStepSnapBackwardEnabled(ActionContext context) {
if (current.getTrace() == null) {
return false;
}
if (!current.getTime().isSnapOnly()) {
return true;
}
if (current.getSnap() <= 0) {
return false;
}
return true;
}
private void activatedStepSnapBackward(ActionContext context) {
if (current.getTime().isSnapOnly()) {
traceManager.activateSnap(current.getSnap() - 1);
}
else {
traceManager.activateSnap(current.getSnap());
}
}
private boolean isEmulateTickBackwardEnabled(ActionContext context) {
if (emulationService == null) {
return false;
}
if (current.getTrace() == null) {
return false;
}
if (current.getTime().steppedBackward(current.getTrace(), 1) == null) {
return false;
}
return true;
}
private void activatedEmulateTickBackward(ActionContext context) {
if (current.getTrace() == null) {
return;
}
TraceSchedule time = current.getTime().steppedBackward(current.getTrace(), 1);
if (time == null) {
return;
}
traceManager.activateTime(time);
}
private boolean isEmulateTickForwardEnabled(ActionContext context) {
if (emulationService == null) {
return false;
}
if (current.getThread() == null) {
return false;
}
return true;
}
private void activatedEmulateTickForward(ActionContext context) {
if (current.getThread() == null) {
return;
}
TraceSchedule time = current.getTime().steppedForward(current.getThread(), 1);
traceManager.activateTime(time);
}
private boolean isEmulateSkipTickForwardEnabled(ActionContext context) {
if (emulationService == null) {
return false;
}
if (current.getThread() == null) {
return false;
}
return true;
}
private void activatedEmulateSkipTickForward(ActionContext context) {
if (current.getThread() == null) {
return;
}
TraceSchedule time = current.getTime().skippedForward(current.getThread(), 1);
traceManager.activateTime(time);
}
private boolean isStepSnapForwardEnabled(ActionContext context) {
Trace curTrace = current.getTrace();
if (curTrace == null) {
return false;
}
Long maxSnap = curTrace.getTimeManager().getMaxSnap();
if (maxSnap == null || current.getSnap() >= maxSnap) {
return false;
}
return true;
}
private void activatedStepSnapForward(ActionContext contetxt) {
traceManager.activateSnap(current.getSnap() + 1);
}
private boolean isSeekTracePresentEnabled(ActionContext context) {
return traceManager != null;
}
private void toggledSeekTracePresent(ActionContext context) {
if (traceManager == null) {
return;
}
traceManager.setAutoActivatePresent(actionSeekTracePresent.isSelected());
}
private void changedAutoActivatePresent(boolean value) {
if (actionSeekTracePresent == null || actionSeekTracePresent.isSelected()) {
return;
}
actionSeekTracePresent.setSelected(value);
}
private void changedSynchronizeFocus(boolean value) {
if (actionSyncFocus == null || actionSyncFocus.isSelected()) {
return;
}
actionSyncFocus.setSelected(value);
}
private void toggleSyncFocus(boolean enabled) {
if (traceManager == null) {
return;