diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/control/DebuggerControlPlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/control/DebuggerControlPlugin.java index a23408fbb8..5dc7d7ee7d 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/control/DebuggerControlPlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/control/DebuggerControlPlugin.java @@ -59,6 +59,7 @@ import ghidra.trace.model.Trace.TraceObjectChangeType; import ghidra.trace.model.target.TraceObject; import ghidra.trace.model.target.TraceObjectValue; import ghidra.trace.model.time.schedule.Scheduler; +import ghidra.trace.model.time.schedule.TraceSchedule; import ghidra.util.*; @PluginInfo( @@ -878,7 +879,8 @@ public class DebuggerControlPlugin extends AbstractDebuggerPlugin return; } DebuggerCoordinates current = this.current; - emulationService.backgroundRun(current.getPlatform(), current.getTime(), + TraceSchedule time = current.getTime(); + emulationService.backgroundRun(current.getPlatform(), time.steppedForward(null, 0), Scheduler.oneThread(current.getThread())).thenAcceptAsync(r -> { traceManager.activate(current.time(r.schedule()), ActivationCause.USER); }, AsyncUtils.SWING_EXECUTOR).exceptionally(ex -> { diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/control/DebuggerControlPluginTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/control/DebuggerControlPluginTest.java index 4df6f83df3..5f20f727c3 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/control/DebuggerControlPluginTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/control/DebuggerControlPluginTest.java @@ -308,6 +308,28 @@ public class DebuggerControlPluginTest extends AbstractGhidraHeadedDebuggerGUITe assertTrue(controlPlugin.actionEmulateResume.isEnabled()); } + /** + * Tests the UI so it does not error when the user presses resume + * after already stepped into a pcode instruction. + */ + @Test + public void testEmulateResumeActionAfterPcodeStep() throws Throwable { + TraceThread thread = createToyLoopTrace(); + controlService.setCurrentMode(tb.trace, ControlMode.RW_EMULATOR); + + traceManager.activateThread(thread); + traceManager.activateTime(TraceSchedule.parse("0:.t0-2")); + waitForSwing(); + + performEnabledAction(null, controlPlugin.actionEmulateResume, true); + waitForPass(() -> assertFalse(controlPlugin.actionEmulateResume.isEnabled())); + + CachedEmulator ce = Unique.assertOne(emulationService.getBusyEmulators()); + ce.emulator().setSuspended(true); + waitForTasks(); + assertTrue(controlPlugin.actionEmulateResume.isEnabled()); + } + @Test public void testEmulateInterruptAction() throws Throwable { TraceThread thread = createToyLoopTrace(); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/menu/DialogToolbarButton.java b/Ghidra/Framework/Docking/src/main/java/docking/menu/DialogToolbarButton.java index 5bf274dc97..fc508388e2 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/menu/DialogToolbarButton.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/menu/DialogToolbarButton.java @@ -21,9 +21,10 @@ import java.beans.PropertyChangeEvent; import docking.DockingWindowManager; import docking.EmptyBorderToggleButton; import docking.action.*; +import ghidra.util.Swing; /** - * Toolbar buttons for Dialogs. + * Toolbar buttons for Dialogs. * *

This class exists because dialog actions are not added to the regular tool's toolbars. This * means that we have to create the dialog's toolbars outside of the tool. Thus, this class @@ -40,7 +41,7 @@ public class DialogToolbarButton extends EmptyBorderToggleButton { addMouseListener(new MouseOverMouseListener()); action.addPropertyChangeListener(propertyChangeListener); - // make sure this button gets our specialized tooltip + // make sure this button gets our specialized tooltip DockingToolBarUtils.setToolTipText(this, dockingAction); } @@ -52,11 +53,18 @@ public class DialogToolbarButton extends EmptyBorderToggleButton { @Override protected void doActionPerformed(ActionEvent e) { + + // The help is pointing to the toolbar button that triggered this call. Reset the help so + // that it is correct for any widgets triggered by the actionPeformed call below. + DockingWindowManager.clearMouseOverHelp(); + if (dockingAction instanceof ToggleDockingActionIf) { ToggleDockingActionIf toggleAction = (ToggleDockingActionIf) dockingAction; toggleAction.setSelected(!toggleAction.isSelected()); } - dockingAction.actionPerformed(contextProvider.getActionContext(null)); + + // Give the Swing thread a chance to repaint + Swing.runLater(() -> dockingAction.actionPerformed(contextProvider.getActionContext(null))); } @Override @@ -84,7 +92,7 @@ public class DialogToolbarButton extends EmptyBorderToggleButton { @Override // overridden to account for the fact that "special" DockableActions can be either - // toggle buttons or regular non-toggle buttons, which dictates whether this + // toggle buttons or regular non-toggle buttons, which dictates whether this // button is selected (non-toggle buttons are not selectable). protected boolean isButtonSelected() { if (dockingAction instanceof ToggleDockingAction) { @@ -101,7 +109,7 @@ public class DialogToolbarButton extends EmptyBorderToggleButton { // overridden to reflect the potentiality that our action is a toggle action public void setSelected(boolean b) { if (dockingAction instanceof ToggleDockingActionIf) { - // only change the state if the action is a toggle action; doing otherwise would + // only change the state if the action is a toggle action; doing otherwise would // break the DockableAction ((ToggleDockingActionIf) dockingAction).setSelected(b); } diff --git a/certification.local.manifest b/certification.local.manifest index 59f4759ca5..58244501fa 100644 --- a/certification.local.manifest +++ b/certification.local.manifest @@ -7,4 +7,5 @@ DevGuide.md||GHIDRA||||END| LICENSE||GHIDRA||||END| NOTICE||GHIDRA||||END| README.md||GHIDRA||||END| +ghidra.repos.config||GHIDRA||||END| gradle.properties||GHIDRA||||END|