mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-25 05:32:14 +00:00
GP-2062: Add Skip Instruction button for emulator
This commit is contained in:
parent
00dbd26511
commit
4736a3c924
@ -120,6 +120,7 @@ src/main/help/help/topics/DebuggerTargetsPlugin/images/disconnect.png||GHIDRA|||
|
|||||||
src/main/help/help/topics/DebuggerThreadsPlugin/DebuggerThreadsPlugin.html||GHIDRA||||END|
|
src/main/help/help/topics/DebuggerThreadsPlugin/DebuggerThreadsPlugin.html||GHIDRA||||END|
|
||||||
src/main/help/help/topics/DebuggerThreadsPlugin/images/DebuggerThreadsPlugin.png||GHIDRA||||END|
|
src/main/help/help/topics/DebuggerThreadsPlugin/images/DebuggerThreadsPlugin.png||GHIDRA||||END|
|
||||||
src/main/help/help/topics/DebuggerThreadsPlugin/images/continue.png||GHIDRA||||END|
|
src/main/help/help/topics/DebuggerThreadsPlugin/images/continue.png||GHIDRA||||END|
|
||||||
|
src/main/help/help/topics/DebuggerThreadsPlugin/images/skipover.png||GHIDRA||||END|
|
||||||
src/main/help/help/topics/DebuggerThreadsPlugin/images/stepback.png||GHIDRA||||END|
|
src/main/help/help/topics/DebuggerThreadsPlugin/images/stepback.png||GHIDRA||||END|
|
||||||
src/main/help/help/topics/DebuggerThreadsPlugin/images/stepinto.png||GHIDRA||||END|
|
src/main/help/help/topics/DebuggerThreadsPlugin/images/stepinto.png||GHIDRA||||END|
|
||||||
src/main/help/help/topics/DebuggerTimePlugin/DebuggerTimePlugin.html||GHIDRA||||END|
|
src/main/help/help/topics/DebuggerTimePlugin/DebuggerTimePlugin.html||GHIDRA||||END|
|
||||||
|
@ -125,6 +125,18 @@
|
|||||||
the next tick, using emulation. Note that emulation does not affect the target. Furthermore,
|
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>
|
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
|
<H3><A name="seek_trace_present"></A><IMG alt="" src="images/continue.png">Seek Trace to
|
||||||
Present</H3>
|
Present</H3>
|
||||||
|
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Binary file not shown.
After Width: | Height: | Size: 320 B |
@ -87,6 +87,7 @@ public interface DebuggerResources {
|
|||||||
|
|
||||||
ImageIcon ICON_STEP_INTO = ResourceManager.loadImage("images/stepinto.png");
|
ImageIcon ICON_STEP_INTO = ResourceManager.loadImage("images/stepinto.png");
|
||||||
ImageIcon ICON_STEP_OVER = ResourceManager.loadImage("images/stepover.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_FINISH = ResourceManager.loadImage("images/stepout.png");
|
||||||
ImageIcon ICON_STEP_BACK = ResourceManager.loadImage("images/stepback.png");
|
ImageIcon ICON_STEP_BACK = ResourceManager.loadImage("images/stepback.png");
|
||||||
// TODO: Draw new icons?
|
// 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 {
|
interface StepSnapBackwardAction {
|
||||||
String NAME = "Step Trace Snap Backward";
|
String NAME = "Step Trace Snap Backward";
|
||||||
String DESCRIPTION = "Navigate the recording backward one snap";
|
String DESCRIPTION = "Navigate the recording backward one snap";
|
||||||
Icon ICON = ICON_SNAP_BACKWARD;
|
Icon ICON = ICON_SNAP_BACKWARD;
|
||||||
String GROUP = GROUP_CONTROL;
|
String GROUP = GROUP_CONTROL;
|
||||||
|
String ORDER = "1";
|
||||||
String HELP_ANCHOR = "step_trace_snap_backward";
|
String HELP_ANCHOR = "step_trace_snap_backward";
|
||||||
|
|
||||||
static ActionBuilder builder(Plugin owner) {
|
static ActionBuilder builder(Plugin owner) {
|
||||||
@ -1723,20 +1655,80 @@ public interface DebuggerResources {
|
|||||||
return new ActionBuilder(NAME, ownerName)
|
return new ActionBuilder(NAME, ownerName)
|
||||||
.description(DESCRIPTION)
|
.description(DESCRIPTION)
|
||||||
.toolBarIcon(ICON)
|
.toolBarIcon(ICON)
|
||||||
.toolBarGroup(GROUP, "1")
|
.toolBarGroup(GROUP, ORDER)
|
||||||
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
|
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class AbstractStepSnapBackwardAction extends DockingAction {
|
interface StepSnapForwardAction {
|
||||||
public static final String NAME = StepSnapBackwardAction.NAME;
|
String NAME = "Step Trace Snap Forward";
|
||||||
public static final Icon ICON = StepSnapBackwardAction.ICON;;
|
String DESCRIPTION = "Navigate the recording forward one snap";
|
||||||
public static final String HELP_ANCHOR = StepSnapBackwardAction.HELP_ANCHOR;
|
Icon ICON = ICON_SNAP_FORWARD;
|
||||||
|
String GROUP = GROUP_CONTROL;
|
||||||
|
String ORDER = "5";
|
||||||
|
String HELP_ANCHOR = "step_trace_snap_forward";
|
||||||
|
|
||||||
public AbstractStepSnapBackwardAction(Plugin owner) {
|
static ActionBuilder builder(Plugin owner) {
|
||||||
super(NAME, owner.getName());
|
String ownerName = owner.getName();
|
||||||
setDescription(StepSnapBackwardAction.DESCRIPTION);
|
return new ActionBuilder(NAME, ownerName)
|
||||||
setHelpLocation(new HelpLocation(owner.getName(), HELP_ANCHOR));
|
.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";
|
String DESCRIPTION = "Navigate the recording backward one p-code tick";
|
||||||
Icon ICON = ICON_STEP_BACK;
|
Icon ICON = ICON_STEP_BACK;
|
||||||
String GROUP = GROUP_CONTROL;
|
String GROUP = GROUP_CONTROL;
|
||||||
|
String ORDER = "2";
|
||||||
String HELP_ANCHOR = "emu_trace_pcode_backward";
|
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) {
|
static ActionBuilder builder(Plugin owner) {
|
||||||
String ownerName = owner.getName();
|
String ownerName = owner.getName();
|
||||||
return new ActionBuilder(NAME, ownerName)
|
return new ActionBuilder(NAME, ownerName)
|
||||||
@ -1757,15 +1786,20 @@ public interface DebuggerResources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class AbstractSeekTracePresentAction extends ToggleDockingAction {
|
interface SeekTracePresentAction {
|
||||||
public static final String NAME = "Seek Trace Present";
|
String NAME = "Seek Trace Present";
|
||||||
public static final Icon ICON = ICON_SEEK_PRESENT;
|
String DESCRIPTION = "Track the tool to the latest snap";
|
||||||
public static final String HELP_ANCHOR = "seek_trace_present";
|
Icon ICON = ICON_SEEK_PRESENT;
|
||||||
|
String GROUP = "zz";
|
||||||
|
String HELP_ANCHOR = "seek_trace_present";
|
||||||
|
|
||||||
public AbstractSeekTracePresentAction(Plugin owner) {
|
static ToggleActionBuilder builder(Plugin owner) {
|
||||||
super(NAME, owner.getName());
|
String ownerName = owner.getName();
|
||||||
setDescription("Track the tool to the latest snap");
|
return new ToggleActionBuilder(NAME, ownerName)
|
||||||
setHelpLocation(new HelpLocation(owner.getName(), HELP_ANCHOR));
|
.description(DESCRIPTION)
|
||||||
|
.toolBarIcon(ICON)
|
||||||
|
.toolBarGroup(GROUP)
|
||||||
|
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,172 +87,6 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter {
|
|||||||
return true;
|
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
|
protected static class ThreadTableModel
|
||||||
extends RowWrappedEnumeratedColumnTableModel< //
|
extends RowWrappedEnumeratedColumnTableModel< //
|
||||||
ThreadTableColumns, ObjectKey, ThreadRow, TraceThread> {
|
ThreadTableColumns, ObjectKey, ThreadRow, TraceThread> {
|
||||||
@ -321,9 +155,9 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter {
|
|||||||
|
|
||||||
private final DebuggerThreadsPlugin plugin;
|
private final DebuggerThreadsPlugin plugin;
|
||||||
|
|
||||||
// @AutoServiceConsumed by method
|
// @AutoServiceConsumed by method
|
||||||
private DebuggerModelService modelService;
|
private DebuggerModelService modelService;
|
||||||
@AutoServiceConsumed // NB, also by method
|
// @AutoServiceConsumed by method
|
||||||
private DebuggerTraceManagerService traceManager;
|
private DebuggerTraceManagerService traceManager;
|
||||||
@AutoServiceConsumed // NB, also by method
|
@AutoServiceConsumed // NB, also by method
|
||||||
private DebuggerEmulationService emulationService;
|
private DebuggerEmulationService emulationService;
|
||||||
@ -337,6 +171,10 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter {
|
|||||||
private final ThreadsListener threadsListener = new ThreadsListener();
|
private final ThreadsListener threadsListener = new ThreadsListener();
|
||||||
private final CollectionChangeListener<TraceRecorder> recordersListener =
|
private final CollectionChangeListener<TraceRecorder> recordersListener =
|
||||||
new RecordersChangeListener();
|
new RecordersChangeListener();
|
||||||
|
private final BooleanChangeAdapter activatePresentChangeListener =
|
||||||
|
this::changedAutoActivatePresent;
|
||||||
|
private final BooleanChangeAdapter synchronizeFocusChangeListener =
|
||||||
|
this::changedSynchronizeFocus;
|
||||||
/* package access for testing */
|
/* package access for testing */
|
||||||
final RangeTableCellRenderer<Long> rangeRenderer = new RangeTableCellRenderer<>();
|
final RangeTableCellRenderer<Long> rangeRenderer = new RangeTableCellRenderer<>();
|
||||||
final RangeCursorTableHeaderRenderer<Long> headerRenderer =
|
final RangeCursorTableHeaderRenderer<Long> headerRenderer =
|
||||||
@ -354,11 +192,12 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter {
|
|||||||
private ActionContext myActionContext;
|
private ActionContext myActionContext;
|
||||||
|
|
||||||
DockingAction actionSaveTrace;
|
DockingAction actionSaveTrace;
|
||||||
StepSnapBackwardAction actionStepSnapBackward;
|
DockingAction actionStepSnapBackward;
|
||||||
EmulateTickBackwardAction actionEmulateTickBackward;
|
DockingAction actionEmulateTickBackward;
|
||||||
EmulateTickForwardAction actionEmulateTickForward;
|
DockingAction actionEmulateTickForward;
|
||||||
StepSnapForwardAction actionStepSnapForward;
|
DockingAction actionEmulateTickSkipForward;
|
||||||
SeekTracePresentAction actionSeekTracePresent;
|
DockingAction actionStepSnapForward;
|
||||||
|
ToggleDockingAction actionSeekTracePresent;
|
||||||
ToggleDockingAction actionSyncFocus;
|
ToggleDockingAction actionSyncFocus;
|
||||||
DockingAction actionGoToTime;
|
DockingAction actionGoToTime;
|
||||||
|
|
||||||
@ -410,9 +249,21 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter {
|
|||||||
|
|
||||||
@AutoServiceConsumed
|
@AutoServiceConsumed
|
||||||
public void setTraceManager(DebuggerTraceManagerService traceManager) {
|
public void setTraceManager(DebuggerTraceManagerService traceManager) {
|
||||||
if (traceManager != null && actionSeekTracePresent != null) {
|
if (this.traceManager != null) {
|
||||||
actionSeekTracePresent.setSelected(traceManager.isAutoActivatePresent());
|
this.traceManager
|
||||||
actionSyncFocus.setSelected(traceManager.isSynchronizeFocus());
|
.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();
|
contextChanged();
|
||||||
}
|
}
|
||||||
@ -633,11 +484,34 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter {
|
|||||||
|
|
||||||
protected void createActions() {
|
protected void createActions() {
|
||||||
// TODO: Make other actions use builder?
|
// TODO: Make other actions use builder?
|
||||||
actionStepSnapBackward = new StepSnapBackwardAction();
|
actionStepSnapBackward = StepSnapBackwardAction.builder(plugin)
|
||||||
actionEmulateTickBackward = new EmulateTickBackwardAction();
|
.enabledWhen(this::isStepSnapBackwardEnabled)
|
||||||
actionEmulateTickForward = new EmulateTickForwardAction();
|
.enabled(false)
|
||||||
actionStepSnapForward = new StepSnapForwardAction();
|
.onAction(this::activatedStepSnapBackward)
|
||||||
actionSeekTracePresent = new SeekTracePresentAction();
|
.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)
|
actionSyncFocus = SynchronizeFocusAction.builder(plugin)
|
||||||
.selected(traceManager != null && traceManager.isSynchronizeFocus())
|
.selected(traceManager != null && traceManager.isSynchronizeFocus())
|
||||||
.enabledWhen(c -> traceManager != null)
|
.enabledWhen(c -> traceManager != null)
|
||||||
@ -672,6 +546,129 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter {
|
|||||||
.buildAndInstallLocal(this);
|
.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) {
|
private void toggleSyncFocus(boolean enabled) {
|
||||||
if (traceManager == null) {
|
if (traceManager == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -0,0 +1,164 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.trace.model.time.schedule;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import ghidra.program.model.lang.Language;
|
||||||
|
|
||||||
|
public abstract class AbstractStep implements Step {
|
||||||
|
protected final long threadKey;
|
||||||
|
protected long tickCount;
|
||||||
|
|
||||||
|
protected AbstractStep(long threadKey, long tickCount) {
|
||||||
|
if (tickCount < 0) {
|
||||||
|
throw new IllegalArgumentException("Cannot step a negative number");
|
||||||
|
}
|
||||||
|
this.threadKey = threadKey;
|
||||||
|
this.tickCount = tickCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the step portion of {@link #toString()}
|
||||||
|
*
|
||||||
|
* @return the string
|
||||||
|
*/
|
||||||
|
protected abstract String toStringStepPart();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
if (threadKey == -1) {
|
||||||
|
return toStringStepPart();
|
||||||
|
}
|
||||||
|
return String.format("t%d-", threadKey) + toStringStepPart();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isNop() {
|
||||||
|
return tickCount == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getThreadKey() {
|
||||||
|
return threadKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getTickCount() {
|
||||||
|
return tickCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getPatchCount() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract AbstractStep clone();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add to the count of this step
|
||||||
|
*
|
||||||
|
* @param steps the count to add
|
||||||
|
*/
|
||||||
|
public void advance(long steps) {
|
||||||
|
if (steps < 0) {
|
||||||
|
throw new IllegalArgumentException("Cannot advance a negative number");
|
||||||
|
}
|
||||||
|
long newCount = tickCount + steps;
|
||||||
|
if (newCount < 0) {
|
||||||
|
throw new IllegalArgumentException("Total step count exceeds LONG_MAX");
|
||||||
|
}
|
||||||
|
this.tickCount = newCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long rewind(long steps) {
|
||||||
|
if (steps < 0) {
|
||||||
|
throw new IllegalArgumentException("Cannot rewind a negative number");
|
||||||
|
}
|
||||||
|
long diff = this.tickCount - steps;
|
||||||
|
this.tickCount = Long.max(0, diff);
|
||||||
|
return -diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCompatible(Step step) {
|
||||||
|
if (!(step.getClass() == this.getClass())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
AbstractStep as = (AbstractStep) step;
|
||||||
|
return this.threadKey == as.threadKey || as.threadKey == -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addTo(Step step) {
|
||||||
|
assert isCompatible(step);
|
||||||
|
AbstractStep as = (AbstractStep) step;
|
||||||
|
advance(as.tickCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Long.hashCode(threadKey) * 31 + Long.hashCode(tickCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj.getClass() != this.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
AbstractStep that = (AbstractStep) obj;
|
||||||
|
if (this.threadKey != that.threadKey) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.tickCount != that.tickCount) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompareResult compareStep(Step step) {
|
||||||
|
CompareResult result;
|
||||||
|
|
||||||
|
result = compareStepType(step);
|
||||||
|
if (result != CompareResult.EQUALS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractStep that = (AbstractStep) step;
|
||||||
|
result = CompareResult.unrelated(Long.compare(this.threadKey, that.threadKey));
|
||||||
|
if (result != CompareResult.EQUALS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = CompareResult.related(Long.compare(this.tickCount, that.tickCount));
|
||||||
|
if (result != CompareResult.EQUALS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CompareResult.EQUALS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long coalescePatches(Language language, List<Step> steps) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
@ -18,7 +18,6 @@ package ghidra.trace.model.time.schedule;
|
|||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import javax.help.UnsupportedOperationException;
|
import javax.help.UnsupportedOperationException;
|
||||||
@ -234,9 +233,8 @@ public class PatchStep implements Step {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getTypeOrder() {
|
public StepType getType() {
|
||||||
// When comparing sequences, those with sleigh steps are ordered after those with ticks
|
return StepType.PATCH;
|
||||||
return 10;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -314,8 +312,8 @@ public class PatchStep implements Step {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> void execute(PcodeThread<T> emuThread, Consumer<PcodeThread<T>> stepAction,
|
public <T> void execute(PcodeThread<T> emuThread, Stepper<T> stepper, TaskMonitor monitor)
|
||||||
TaskMonitor monitor) throws CancelledException {
|
throws CancelledException {
|
||||||
PcodeProgram prog = emuThread.getMachine().compileSleigh("schedule", List.of(sleigh + ";"));
|
PcodeProgram prog = emuThread.getMachine().compileSleigh("schedule", List.of(sleigh + ";"));
|
||||||
emuThread.getExecutor().execute(prog, emuThread.getUseropLibrary());
|
emuThread.getExecutor().execute(prog, emuThread.getUseropLibrary());
|
||||||
}
|
}
|
||||||
|
@ -16,13 +16,11 @@
|
|||||||
package ghidra.trace.model.time.schedule;
|
package ghidra.trace.model.time.schedule;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import ghidra.pcode.emu.PcodeMachine;
|
import ghidra.pcode.emu.PcodeMachine;
|
||||||
import ghidra.pcode.emu.PcodeThread;
|
|
||||||
import ghidra.program.model.lang.Language;
|
import ghidra.program.model.lang.Language;
|
||||||
import ghidra.trace.model.Trace;
|
import ghidra.trace.model.Trace;
|
||||||
import ghidra.trace.model.thread.TraceThread;
|
import ghidra.trace.model.thread.TraceThread;
|
||||||
@ -381,17 +379,17 @@ public class Sequence implements Comparable<Sequence> {
|
|||||||
* @param trace the trace to which the machine is bound
|
* @param trace the trace to which the machine is bound
|
||||||
* @param eventThread the thread for the first step, if it applies to the "last thread"
|
* @param eventThread the thread for the first step, if it applies to the "last thread"
|
||||||
* @param machine the machine to step, or null to validate the sequence
|
* @param machine the machine to step, or null to validate the sequence
|
||||||
* @param action the action to step each thread
|
* @param stepper the actions to step each thread
|
||||||
* @param monitor a monitor for cancellation and progress reports
|
* @param monitor a monitor for cancellation and progress reports
|
||||||
* @return the last trace thread stepped during execution
|
* @return the last trace thread stepped during execution
|
||||||
* @throws CancelledException if execution is cancelled
|
* @throws CancelledException if execution is cancelled
|
||||||
*/
|
*/
|
||||||
public <T> TraceThread execute(Trace trace, TraceThread eventThread, PcodeMachine<T> machine,
|
public <T> TraceThread execute(Trace trace, TraceThread eventThread, PcodeMachine<T> machine,
|
||||||
Consumer<PcodeThread<T>> action, TaskMonitor monitor) throws CancelledException {
|
Stepper<T> stepper, TaskMonitor monitor) throws CancelledException {
|
||||||
TraceThreadManager tm = trace.getThreadManager();
|
TraceThreadManager tm = trace.getThreadManager();
|
||||||
TraceThread thread = eventThread;
|
TraceThread thread = eventThread;
|
||||||
for (Step step : steps) {
|
for (Step step : steps) {
|
||||||
thread = step.execute(tm, thread, machine, action, monitor);
|
thread = step.execute(tm, thread, machine, stepper, monitor);
|
||||||
}
|
}
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,77 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.trace.model.time.schedule;
|
||||||
|
|
||||||
|
import ghidra.pcode.emu.PcodeThread;
|
||||||
|
import ghidra.util.exception.CancelledException;
|
||||||
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
|
public class SkipStep extends AbstractStep {
|
||||||
|
|
||||||
|
public static SkipStep parse(long threadKey, String stepSpec) {
|
||||||
|
if (!stepSpec.startsWith("s")) {
|
||||||
|
throw new IllegalArgumentException("Cannot parse skip step: '" + stepSpec + "'");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return new SkipStep(threadKey, Long.parseLong(stepSpec.substring(1)));
|
||||||
|
}
|
||||||
|
catch (NumberFormatException e) {
|
||||||
|
throw new IllegalArgumentException("Cannot parse skip step: '" + stepSpec + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a skip step for the given thread with the given tick count
|
||||||
|
*
|
||||||
|
* @param threadKey the key of the thread in the trace, -1 for the "last thread"
|
||||||
|
* @param tickCount the number of ticks to skip on the thread
|
||||||
|
*/
|
||||||
|
public SkipStep(long threadKey, long tickCount) {
|
||||||
|
super(threadKey, tickCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StepType getType() {
|
||||||
|
return StepType.SKIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String toStringStepPart() {
|
||||||
|
return String.format("s%d", tickCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AbstractStep clone() {
|
||||||
|
return new SkipStep(threadKey, tickCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Step subtract(Step step) {
|
||||||
|
assert isCompatible(step);
|
||||||
|
SkipStep that = (SkipStep) step;
|
||||||
|
return new SkipStep(this.threadKey, this.tickCount - that.tickCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> void execute(PcodeThread<T> emuThread, Stepper<T> stepper, TaskMonitor monitor)
|
||||||
|
throws CancelledException {
|
||||||
|
for (int i = 0; i < tickCount; i++) {
|
||||||
|
monitor.incrementProgress(1);
|
||||||
|
monitor.checkCanceled();
|
||||||
|
stepper.skip(emuThread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -16,7 +16,6 @@
|
|||||||
package ghidra.trace.model.time.schedule;
|
package ghidra.trace.model.time.schedule;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
import ghidra.pcode.emu.PcodeMachine;
|
import ghidra.pcode.emu.PcodeMachine;
|
||||||
import ghidra.pcode.emu.PcodeThread;
|
import ghidra.pcode.emu.PcodeThread;
|
||||||
@ -27,6 +26,12 @@ import ghidra.util.exception.CancelledException;
|
|||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public interface Step extends Comparable<Step> {
|
public interface Step extends Comparable<Step> {
|
||||||
|
enum StepType {
|
||||||
|
TICK,
|
||||||
|
SKIP,
|
||||||
|
PATCH,
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a step, possibly including a thread prefix, e.g., {@code "t1-..."}
|
* Parse a step, possibly including a thread prefix, e.g., {@code "t1-..."}
|
||||||
*
|
*
|
||||||
@ -69,6 +74,9 @@ public interface Step extends Comparable<Step> {
|
|||||||
* @throws IllegalArgumentException if the specification is of the wrong form
|
* @throws IllegalArgumentException if the specification is of the wrong form
|
||||||
*/
|
*/
|
||||||
static Step parse(long threadKey, String stepSpec) {
|
static Step parse(long threadKey, String stepSpec) {
|
||||||
|
if (stepSpec.startsWith("s")) {
|
||||||
|
return SkipStep.parse(threadKey, stepSpec);
|
||||||
|
}
|
||||||
if (stepSpec.startsWith("{")) {
|
if (stepSpec.startsWith("{")) {
|
||||||
return PatchStep.parse(threadKey, stepSpec);
|
return PatchStep.parse(threadKey, stepSpec);
|
||||||
}
|
}
|
||||||
@ -79,7 +87,11 @@ public interface Step extends Comparable<Step> {
|
|||||||
return new TickStep(-1, 0);
|
return new TickStep(-1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int getTypeOrder();
|
StepType getType();
|
||||||
|
|
||||||
|
default int getTypeOrder() {
|
||||||
|
return getType().ordinal();
|
||||||
|
}
|
||||||
|
|
||||||
boolean isNop();
|
boolean isNop();
|
||||||
|
|
||||||
@ -159,7 +171,7 @@ public interface Step extends Comparable<Step> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default <T> TraceThread execute(TraceThreadManager tm, TraceThread eventThread,
|
default <T> TraceThread execute(TraceThreadManager tm, TraceThread eventThread,
|
||||||
PcodeMachine<T> machine, Consumer<PcodeThread<T>> stepAction, TaskMonitor monitor)
|
PcodeMachine<T> machine, Stepper<T> stepper, TaskMonitor monitor)
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
TraceThread thread = getThread(tm, eventThread);
|
TraceThread thread = getThread(tm, eventThread);
|
||||||
if (machine == null) {
|
if (machine == null) {
|
||||||
@ -167,12 +179,12 @@ public interface Step extends Comparable<Step> {
|
|||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
PcodeThread<T> emuThread = machine.getThread(thread.getPath(), true);
|
PcodeThread<T> emuThread = machine.getThread(thread.getPath(), true);
|
||||||
execute(emuThread, stepAction, monitor);
|
execute(emuThread, stepper, monitor);
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
<T> void execute(PcodeThread<T> emuThread, Consumer<PcodeThread<T>> stepAction,
|
<T> void execute(PcodeThread<T> emuThread, Stepper<T> stepper, TaskMonitor monitor)
|
||||||
TaskMonitor monitor) throws CancelledException;
|
throws CancelledException;
|
||||||
|
|
||||||
long coalescePatches(Language language, List<Step> steps);
|
long coalescePatches(Language language, List<Step> steps);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.trace.model.time.schedule;
|
||||||
|
|
||||||
|
import ghidra.pcode.emu.PcodeThread;
|
||||||
|
|
||||||
|
public interface Stepper<T> {
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
enum Enum implements Stepper {
|
||||||
|
INSTRUCTION {
|
||||||
|
@Override
|
||||||
|
public void tick(PcodeThread thread) {
|
||||||
|
thread.stepInstruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void skip(PcodeThread thread) {
|
||||||
|
thread.skipInstruction();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
PCODE {
|
||||||
|
@Override
|
||||||
|
public void tick(PcodeThread thread) {
|
||||||
|
thread.stepPcodeOp();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void skip(PcodeThread thread) {
|
||||||
|
thread.skipPcodeOp();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
static <T> Stepper<T> instruction() {
|
||||||
|
return Enum.INSTRUCTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
static <T> Stepper<T> pcode() {
|
||||||
|
return Enum.PCODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tick(PcodeThread<T> thread);
|
||||||
|
|
||||||
|
void skip(PcodeThread<T> thread);
|
||||||
|
}
|
@ -15,76 +15,42 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.trace.model.time.schedule;
|
package ghidra.trace.model.time.schedule;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
import ghidra.pcode.emu.PcodeThread;
|
import ghidra.pcode.emu.PcodeThread;
|
||||||
import ghidra.program.model.lang.Language;
|
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A step of a given thread in a schedule: repeating some number of ticks
|
* A step of a given thread in a schedule: repeating some number of ticks
|
||||||
*/
|
*/
|
||||||
public class TickStep implements Step {
|
public class TickStep extends AbstractStep {
|
||||||
|
|
||||||
public static TickStep parse(long threadKey, String stepSpec) {
|
public static TickStep parse(long threadKey, String stepSpec) {
|
||||||
try {
|
try {
|
||||||
return new TickStep(threadKey, Long.parseLong(stepSpec));
|
return new TickStep(threadKey, Long.parseLong(stepSpec));
|
||||||
}
|
}
|
||||||
catch (NumberFormatException e) {
|
catch (NumberFormatException e) {
|
||||||
throw new IllegalArgumentException("Cannot parse step: '" + stepSpec + "'");
|
throw new IllegalArgumentException("Cannot parse tick step: '" + stepSpec + "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final long threadKey;
|
|
||||||
protected long tickCount;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a step for the given thread with the given tick count
|
* Construct a tick step for the given thread with the given tick count
|
||||||
*
|
*
|
||||||
* @param threadKey the key of the thread in the trace, -1 for the "last thread"
|
* @param threadKey the key of the thread in the trace, -1 for the "last thread"
|
||||||
* @param tickCount the number of times to step the thread
|
* @param tickCount the number of ticks to step on the thread
|
||||||
*/
|
*/
|
||||||
public TickStep(long threadKey, long tickCount) {
|
public TickStep(long threadKey, long tickCount) {
|
||||||
if (tickCount < 0) {
|
super(threadKey, tickCount);
|
||||||
throw new IllegalArgumentException("Cannot step a negative number");
|
|
||||||
}
|
|
||||||
this.threadKey = threadKey;
|
|
||||||
this.tickCount = tickCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getTypeOrder() {
|
public StepType getType() {
|
||||||
return 0;
|
return StepType.TICK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
protected String toStringStepPart() {
|
||||||
if (threadKey == -1) {
|
return Long.toString(tickCount);
|
||||||
return Long.toString(tickCount);
|
|
||||||
}
|
|
||||||
return String.format("t%d-%d", threadKey, tickCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isNop() {
|
|
||||||
return tickCount == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getThreadKey() {
|
|
||||||
return threadKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getTickCount() {
|
|
||||||
return tickCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getPatchCount() {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -92,48 +58,6 @@ public class TickStep implements Step {
|
|||||||
return new TickStep(threadKey, tickCount);
|
return new TickStep(threadKey, tickCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Add to the count of this step
|
|
||||||
*
|
|
||||||
* @param steps the count to add
|
|
||||||
*/
|
|
||||||
public void advance(long steps) {
|
|
||||||
if (steps < 0) {
|
|
||||||
throw new IllegalArgumentException("Cannot advance a negative number");
|
|
||||||
}
|
|
||||||
long newCount = tickCount + steps;
|
|
||||||
if (newCount < 0) {
|
|
||||||
throw new IllegalArgumentException("Total step count exceeds LONG_MAX");
|
|
||||||
}
|
|
||||||
this.tickCount = newCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long rewind(long steps) {
|
|
||||||
if (steps < 0) {
|
|
||||||
throw new IllegalArgumentException("Cannot rewind a negative number");
|
|
||||||
}
|
|
||||||
long diff = this.tickCount - steps;
|
|
||||||
this.tickCount = Long.max(0, diff);
|
|
||||||
return -diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCompatible(Step step) {
|
|
||||||
if (!(step instanceof TickStep)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
TickStep ts = (TickStep) step;
|
|
||||||
return this.threadKey == ts.threadKey || ts.threadKey == -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addTo(Step step) {
|
|
||||||
assert isCompatible(step);
|
|
||||||
TickStep ts = (TickStep) step;
|
|
||||||
advance(ts.tickCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Step subtract(Step step) {
|
public Step subtract(Step step) {
|
||||||
assert isCompatible(step);
|
assert isCompatible(step);
|
||||||
@ -142,63 +66,12 @@ public class TickStep implements Step {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public <T> void execute(PcodeThread<T> emuThread, Stepper<T> stepper, TaskMonitor monitor)
|
||||||
return Long.hashCode(threadKey) * 31 + Long.hashCode(tickCount);
|
throws CancelledException {
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (this == obj) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!(obj instanceof TickStep)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
TickStep that = (TickStep) obj;
|
|
||||||
if (this.threadKey != that.threadKey) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (this.tickCount != that.tickCount) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompareResult compareStep(Step step) {
|
|
||||||
CompareResult result;
|
|
||||||
|
|
||||||
result = compareStepType(step);
|
|
||||||
if (result != CompareResult.EQUALS) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
TickStep that = (TickStep) step;
|
|
||||||
result = CompareResult.unrelated(Long.compare(this.threadKey, that.threadKey));
|
|
||||||
if (result != CompareResult.EQUALS) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = CompareResult.related(Long.compare(this.tickCount, that.tickCount));
|
|
||||||
if (result != CompareResult.EQUALS) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CompareResult.EQUALS;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> void execute(PcodeThread<T> emuThread, Consumer<PcodeThread<T>> stepAction,
|
|
||||||
TaskMonitor monitor) throws CancelledException {
|
|
||||||
for (int i = 0; i < tickCount; i++) {
|
for (int i = 0; i < tickCount; i++) {
|
||||||
monitor.incrementProgress(1);
|
monitor.incrementProgress(1);
|
||||||
monitor.checkCanceled();
|
monitor.checkCanceled();
|
||||||
stepAction.accept(emuThread);
|
stepper.tick(emuThread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public long coalescePatches(Language language, List<Step> steps) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,6 @@ package ghidra.trace.model.time.schedule;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import ghidra.pcode.emu.PcodeMachine;
|
import ghidra.pcode.emu.PcodeMachine;
|
||||||
import ghidra.pcode.emu.PcodeThread;
|
|
||||||
import ghidra.trace.model.Trace;
|
import ghidra.trace.model.Trace;
|
||||||
import ghidra.trace.model.thread.TraceThread;
|
import ghidra.trace.model.thread.TraceThread;
|
||||||
import ghidra.trace.model.time.TraceSnapshot;
|
import ghidra.trace.model.time.TraceSnapshot;
|
||||||
@ -339,9 +338,9 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
TraceThread lastThread = getEventThread(trace);
|
TraceThread lastThread = getEventThread(trace);
|
||||||
lastThread =
|
lastThread =
|
||||||
steps.execute(trace, lastThread, machine, PcodeThread::stepInstruction, monitor);
|
steps.execute(trace, lastThread, machine, Stepper.instruction(), monitor);
|
||||||
lastThread =
|
lastThread =
|
||||||
pSteps.execute(trace, lastThread, machine, PcodeThread::stepPcodeOp, monitor);
|
pSteps.execute(trace, lastThread, machine, Stepper.pcode(), monitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -383,13 +382,13 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||||||
if (remains.isNop()) {
|
if (remains.isNop()) {
|
||||||
Sequence pRemains = this.pSteps.relativize(position.pSteps);
|
Sequence pRemains = this.pSteps.relativize(position.pSteps);
|
||||||
lastThread =
|
lastThread =
|
||||||
pRemains.execute(trace, lastThread, machine, PcodeThread::stepPcodeOp, monitor);
|
pRemains.execute(trace, lastThread, machine, Stepper.pcode(), monitor);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lastThread =
|
lastThread =
|
||||||
remains.execute(trace, lastThread, machine, PcodeThread::stepInstruction, monitor);
|
remains.execute(trace, lastThread, machine, Stepper.instruction(), monitor);
|
||||||
lastThread =
|
lastThread =
|
||||||
pSteps.execute(trace, lastThread, machine, PcodeThread::stepPcodeOp, monitor);
|
pSteps.execute(trace, lastThread, machine, Stepper.pcode(), monitor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -411,6 +410,19 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||||||
return new TraceSchedule(snap, steps, new Sequence());
|
return new TraceSchedule(snap, steps, new Sequence());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Behaves as in {@link #steppedForward(TraceThread, long)}, but by appending skips
|
||||||
|
*
|
||||||
|
* @param thread the thread to step, or null for the "last thread"
|
||||||
|
* @param tickCount the number of skips to take the thread forward
|
||||||
|
* @return the resulting schedule
|
||||||
|
*/
|
||||||
|
public TraceSchedule skippedForward(TraceThread thread, long tickCount) {
|
||||||
|
Sequence steps = this.steps.clone();
|
||||||
|
steps.advance(new SkipStep(thread == null ? -1 : thread.getKey(), tickCount));
|
||||||
|
return new TraceSchedule(snap, steps, new Sequence());
|
||||||
|
}
|
||||||
|
|
||||||
protected TraceSchedule doSteppedBackward(Trace trace, long tickCount, Set<Long> visited) {
|
protected TraceSchedule doSteppedBackward(Trace trace, long tickCount, Set<Long> visited) {
|
||||||
if (!visited.add(snap)) {
|
if (!visited.add(snap)) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.trace.model.time.schedule;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import ghidra.pcode.emu.AbstractPcodeMachine;
|
||||||
|
import ghidra.pcode.emu.PcodeThread;
|
||||||
|
import ghidra.pcode.exec.PcodeExecutorState;
|
||||||
|
import ghidra.pcode.exec.PcodeUseropLibrary;
|
||||||
|
|
||||||
|
class TestMachine extends AbstractPcodeMachine<Void> {
|
||||||
|
protected final List<String> record = new ArrayList<>();
|
||||||
|
|
||||||
|
public TestMachine() {
|
||||||
|
super(TraceScheduleTest.TOY_BE_64_LANG, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PcodeThread<Void> createThread(String name) {
|
||||||
|
return new TestThread(name, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PcodeExecutorState<Void> createSharedState() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PcodeExecutorState<Void> createLocalState(PcodeThread<Void> thread) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PcodeUseropLibrary<Void> createUseropLibrary() {
|
||||||
|
return PcodeUseropLibrary.nil();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,162 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.trace.model.time.schedule;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import ghidra.pcode.emu.PcodeThread;
|
||||||
|
import ghidra.pcode.emu.ThreadPcodeExecutorState;
|
||||||
|
import ghidra.pcode.exec.*;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.lang.RegisterValue;
|
||||||
|
import ghidra.program.model.listing.Instruction;
|
||||||
|
|
||||||
|
class TestThread implements PcodeThread<Void> {
|
||||||
|
protected final String name;
|
||||||
|
protected final TestMachine machine;
|
||||||
|
|
||||||
|
public TestThread(String name, TestMachine machine) {
|
||||||
|
this.name = name;
|
||||||
|
this.machine = machine;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TestMachine getMachine() {
|
||||||
|
return machine;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PcodeExecutor<Void> getExecutor() {
|
||||||
|
return new PcodeExecutor<>(TraceScheduleTest.TOY_BE_64_LANG, machine.getArithmetic(), getState()) {
|
||||||
|
public PcodeFrame execute(PcodeProgram program, PcodeUseropLibrary<Void> library) {
|
||||||
|
machine.record.add("x:" + name);
|
||||||
|
// TODO: Verify the actual effect
|
||||||
|
return null; //super.execute(program, library);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stepInstruction() {
|
||||||
|
machine.record.add("ti:" + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void skipInstruction() {
|
||||||
|
machine.record.add("si:" + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stepPcodeOp() {
|
||||||
|
machine.record.add("tp:" + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void skipPcodeOp() {
|
||||||
|
machine.record.add("sp:" + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCounter(Address counter) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Address getCounter() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void overrideCounter(Address counter) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void assignContext(RegisterValue context) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RegisterValue getContext() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void overrideContext(RegisterValue context) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void overrideContextWithDefault() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reInitialize() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PcodeFrame getFrame() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Instruction getInstruction() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void executeInstruction() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finishInstruction() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dropInstruction() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSuspended(boolean suspended) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PcodeUseropLibrary<Void> getUseropLibrary() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ThreadPcodeExecutorState<Void> getState() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void inject(Address address, List<String> sleigh) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearInject(Address address) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearAllInjects() {
|
||||||
|
}
|
||||||
|
}
|
@ -17,18 +17,14 @@ package ghidra.trace.model.time.schedule;
|
|||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||||
import ghidra.pcode.emu.*;
|
import ghidra.program.model.lang.LanguageID;
|
||||||
import ghidra.pcode.exec.*;
|
import ghidra.program.model.lang.LanguageNotFoundException;
|
||||||
import ghidra.program.model.address.Address;
|
|
||||||
import ghidra.program.model.lang.*;
|
|
||||||
import ghidra.program.model.listing.Instruction;
|
|
||||||
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
|
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
|
||||||
import ghidra.test.ToyProgramBuilder;
|
import ghidra.test.ToyProgramBuilder;
|
||||||
import ghidra.trace.database.ToyDBTraceBuilder;
|
import ghidra.trace.database.ToyDBTraceBuilder;
|
||||||
@ -267,165 +263,6 @@ public class TraceScheduleTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||||||
assertEquals(15, TraceSchedule.parse("0:4;t1-5.6").totalTickCount());
|
assertEquals(15, TraceSchedule.parse("0:4;t1-5.6").totalTickCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class TestThread implements PcodeThread<Void> {
|
|
||||||
protected final String name;
|
|
||||||
protected final TestMachine machine;
|
|
||||||
|
|
||||||
public TestThread(String name, TestMachine machine) {
|
|
||||||
this.name = name;
|
|
||||||
this.machine = machine;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TestMachine getMachine() {
|
|
||||||
return machine;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setCounter(Address counter) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Address getCounter() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void overrideCounter(Address counter) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void assignContext(RegisterValue context) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RegisterValue getContext() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void overrideContext(RegisterValue context) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void overrideContextWithDefault() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reInitialize() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stepInstruction() {
|
|
||||||
machine.record.add("s:" + name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stepPcodeOp() {
|
|
||||||
machine.record.add("p:" + name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PcodeFrame getFrame() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Instruction getInstruction() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void executeInstruction() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void finishInstruction() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void skipInstruction() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dropInstruction() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSuspended(boolean suspended) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PcodeExecutor<Void> getExecutor() {
|
|
||||||
return new PcodeExecutor<>(TOY_BE_64_LANG, machine.getArithmetic(), getState()) {
|
|
||||||
public PcodeFrame execute(PcodeProgram program, PcodeUseropLibrary<Void> library) {
|
|
||||||
machine.record.add("x:" + name);
|
|
||||||
// TODO: Verify the actual effect
|
|
||||||
return null; //super.execute(program, library);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PcodeUseropLibrary<Void> getUseropLibrary() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ThreadPcodeExecutorState<Void> getState() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void inject(Address address, List<String> sleigh) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearInject(Address address) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearAllInjects() {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static class TestMachine extends AbstractPcodeMachine<Void> {
|
|
||||||
protected final List<String> record = new ArrayList<>();
|
|
||||||
|
|
||||||
public TestMachine() {
|
|
||||||
super(TOY_BE_64_LANG, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected PcodeThread<Void> createThread(String name) {
|
|
||||||
return new TestThread(name, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected PcodeExecutorState<Void> createSharedState() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected PcodeExecutorState<Void> createLocalState(PcodeThread<Void> thread) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected PcodeUseropLibrary<Void> createUseropLibrary() {
|
|
||||||
return PcodeUseropLibrary.nil();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExecute() throws Exception {
|
public void testExecute() throws Exception {
|
||||||
TestMachine machine = new TestMachine();
|
TestMachine machine = new TestMachine();
|
||||||
@ -442,16 +279,45 @@ public class TraceScheduleTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assertEquals(List.of(
|
assertEquals(List.of(
|
||||||
"s:Threads[2]",
|
"ti:Threads[2]",
|
||||||
"s:Threads[2]",
|
"ti:Threads[2]",
|
||||||
"s:Threads[2]",
|
"ti:Threads[2]",
|
||||||
"s:Threads[2]",
|
"ti:Threads[2]",
|
||||||
"s:Threads[0]",
|
"ti:Threads[0]",
|
||||||
"s:Threads[0]",
|
"ti:Threads[0]",
|
||||||
"s:Threads[0]",
|
"ti:Threads[0]",
|
||||||
"s:Threads[1]",
|
"ti:Threads[1]",
|
||||||
"s:Threads[1]",
|
"ti:Threads[1]",
|
||||||
"p:Threads[1]"),
|
"tp:Threads[1]"),
|
||||||
|
machine.record);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExecuteWithSkips() throws Exception {
|
||||||
|
TestMachine machine = new TestMachine();
|
||||||
|
TraceSchedule time = TraceSchedule.parse("1:4;t0-s3;t1-2.s1");
|
||||||
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("test", ToyProgramBuilder._TOY64_BE)) {
|
||||||
|
TraceThread t2;
|
||||||
|
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||||
|
tb.trace.getThreadManager().createThread("Threads[0]", 0);
|
||||||
|
tb.trace.getThreadManager().createThread("Threads[1]", 0);
|
||||||
|
t2 = tb.trace.getThreadManager().createThread("Threads[2]", 0);
|
||||||
|
tb.trace.getTimeManager().getSnapshot(1, true).setEventThread(t2);
|
||||||
|
}
|
||||||
|
time.execute(tb.trace, machine, TaskMonitor.DUMMY);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(List.of(
|
||||||
|
"ti:Threads[2]",
|
||||||
|
"ti:Threads[2]",
|
||||||
|
"ti:Threads[2]",
|
||||||
|
"ti:Threads[2]",
|
||||||
|
"si:Threads[0]",
|
||||||
|
"si:Threads[0]",
|
||||||
|
"si:Threads[0]",
|
||||||
|
"ti:Threads[1]",
|
||||||
|
"ti:Threads[1]",
|
||||||
|
"sp:Threads[1]"),
|
||||||
machine.record);
|
machine.record);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -472,10 +338,10 @@ public class TraceScheduleTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||||||
|
|
||||||
assertEquals(List.of(
|
assertEquals(List.of(
|
||||||
"x:Threads[2]",
|
"x:Threads[2]",
|
||||||
"s:Threads[2]",
|
"ti:Threads[2]",
|
||||||
"s:Threads[2]",
|
"ti:Threads[2]",
|
||||||
"s:Threads[2]",
|
"ti:Threads[2]",
|
||||||
"s:Threads[2]"),
|
"ti:Threads[2]"),
|
||||||
machine.record);
|
machine.record);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -526,10 +392,10 @@ public class TraceScheduleTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assertEquals(List.of(
|
assertEquals(List.of(
|
||||||
"s:Threads[0]",
|
"ti:Threads[0]",
|
||||||
"s:Threads[1]",
|
"ti:Threads[1]",
|
||||||
"s:Threads[1]",
|
"ti:Threads[1]",
|
||||||
"p:Threads[1]"),
|
"tp:Threads[1]"),
|
||||||
machine.record);
|
machine.record);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -550,7 +416,7 @@ public class TraceScheduleTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assertEquals(List.of(
|
assertEquals(List.of(
|
||||||
"p:Threads[1]"),
|
"tp:Threads[1]"),
|
||||||
machine.record);
|
machine.record);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,6 +364,19 @@ public class DefaultPcodeThread<T> implements PcodeThread<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void skipPcodeOp() {
|
||||||
|
if (frame == null) {
|
||||||
|
beginInstructionOrInject();
|
||||||
|
}
|
||||||
|
else if (!frame.isFinished()) {
|
||||||
|
executor.skip(frame);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
advanceAfterFinished();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start execution of the instruction or inject at the program counter
|
* Start execution of the instruction or inject at the program counter
|
||||||
*/
|
*/
|
||||||
|
@ -184,6 +184,18 @@ public interface PcodeThread<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Skip emulation of a single p-code operation
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* If there is no current frame, this behaves as in {@link #stepPcodeOp()}. Otherwise, this
|
||||||
|
* skips the current pcode op, advancing as if a fall-through op. If no ops remain in the frame,
|
||||||
|
* this behaves as in {@link #stepPcodeOp()}. Please note to skip an extranal branch, the op
|
||||||
|
* itself must be skipped. "Skipping" the following op, which disposes the frame, cannot prevent
|
||||||
|
* the branch.
|
||||||
|
*/
|
||||||
|
void skipPcodeOp();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current frame, if present
|
* Get the current frame, if present
|
||||||
*
|
*
|
||||||
|
@ -211,6 +211,10 @@ public class PcodeExecutor<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void skip(PcodeFrame frame) {
|
||||||
|
frame.nextOp();
|
||||||
|
}
|
||||||
|
|
||||||
protected int getIntConst(Varnode vn) {
|
protected int getIntConst(Varnode vn) {
|
||||||
assert vn.getAddress().getAddressSpace().isConstantSpace();
|
assert vn.getAddress().getAddressSpace().isConstantSpace();
|
||||||
return (int) vn.getAddress().getOffset();
|
return (int) vn.getAddress().getOffset();
|
||||||
|
Loading…
Reference in New Issue
Block a user