GP-4101: Update Debugger help

This commit is contained in:
Dan 2023-12-04 16:04:47 -05:00
parent 58e22a6f7b
commit bb0ba16ab0
19 changed files with 229 additions and 116 deletions

View file

@ -15,14 +15,22 @@
*/
package ghidra.app.plugin.core.debug.gui.breakpoint;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import java.awt.event.MouseEvent;
import java.util.List;
import java.util.Set;
import org.junit.Before;
import org.junit.Test;
import db.Transaction;
import docking.DefaultActionContext;
import docking.menu.ActionState;
import docking.menu.MultiStateDockingAction;
import generic.Unique;
import generic.test.TestUtils;
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerTest.TestDebuggerTargetTraceMapper;
import ghidra.app.plugin.core.debug.service.breakpoint.DebuggerLogicalBreakpointServicePlugin;
@ -31,6 +39,11 @@ import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingService
import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin;
import ghidra.app.plugin.core.decompile.DecompilePlugin;
import ghidra.app.plugin.core.decompile.DecompilerProvider;
import ghidra.app.plugin.core.functiongraph.FGProvider;
import ghidra.app.plugin.core.functiongraph.FunctionGraphPlugin;
import ghidra.app.plugin.core.functiongraph.graph.*;
import ghidra.app.plugin.core.functiongraph.graph.vertex.FGVertex;
import ghidra.app.plugin.core.functiongraph.mvc.*;
import ghidra.app.plugin.core.progmgr.ProgramManagerPlugin;
import ghidra.app.services.*;
import ghidra.app.util.viewer.listingpanel.ListingPanel;
@ -39,6 +52,7 @@ import ghidra.debug.api.action.ActionSource;
import ghidra.debug.api.breakpoint.LogicalBreakpoint;
import ghidra.debug.api.breakpoint.LogicalBreakpoint.State;
import ghidra.debug.api.model.TraceRecorder;
import ghidra.graph.viewer.VisualGraphViewUpdater;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ProgramLocation;
@ -46,6 +60,7 @@ import ghidra.trace.model.*;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.util.Msg;
import ghidra.util.Swing;
import ghidra.util.task.RunManager;
import ghidra.util.task.TaskMonitor;
import help.screenshot.GhidraScreenShotGenerator;
@ -85,6 +100,8 @@ public class DebuggerBreakpointMarkerPluginScreenShots extends GhidraScreenShotG
public void testCaptureDebuggerBreakpointMarkerPlugin() throws Throwable {
ListingPanel panel = listing.getListingPanel();
moveProviderToItsOwnWindow(listing, 1024, 680);
mb.createTestModel();
modelService.addModel(mb.testModel);
mb.createTestProcessesAndThreads();
@ -114,6 +131,7 @@ public class DebuggerBreakpointMarkerPluginScreenShots extends GhidraScreenShotG
Msg.debug(this, "Disabling breakpoint");
LogicalBreakpoint lb = waitForValue(() -> Unique.assertAtMostOne(
breakpointService.getBreakpointsAt(program, addr(program, 0x00401c60))));
waitForCondition(() -> lb.computeState() == State.ENABLED);
lb.disable();
waitForCondition(() -> lb.computeState() == State.DISABLED);
@ -133,6 +151,152 @@ public class DebuggerBreakpointMarkerPluginScreenShots extends GhidraScreenShotG
captureProviderWithScreenShot(listing);
}
protected FGController getFunctionGraphController(FGProvider fgProvider) {
return (FGController) TestUtils.getInstanceField("controller", fgProvider);
}
protected void waitForBusyRunManager(FGController controller) {
FGModel model = controller.getModel();
// long start = System.nanoTime();
waitForSwing();
RunManager runManager = (RunManager) TestUtils.getInstanceField("runManager", model);
waitForCondition(() -> !runManager.isInProgress());
// long end = System.nanoTime();
// long total = end - start;
// Msg.debug(this,
// "Run manager wait time: " + TimeUnit.MILLISECONDS.convert(total, TimeUnit.NANOSECONDS));
}
protected FGComponent getGraphComponent(FGProvider fgProvider) {
FGController controller =
(FGController) TestUtils.getInstanceField("controller", fgProvider);
FGView view = (FGView) TestUtils.getInstanceField("view", controller);
return (FGComponent) TestUtils.getInstanceField("fgComponent", view);
}
protected FGPrimaryViewer getPrimaryGraphViewer(FGProvider fgProvider) {
FGComponent component = getGraphComponent(fgProvider);
if (component == null) {
return null; // this will be null if the graph has been disposed
}
assertNotNull("FG GraphComponent should not be null", component);
return (FGPrimaryViewer) getInstanceField("primaryViewer", component);
}
protected VisualGraphViewUpdater<FGVertex, FGEdge> getGraphUpdater(FGProvider fgProvider) {
FGPrimaryViewer viewer = getPrimaryGraphViewer(fgProvider);
if (viewer == null) {
return null; // this can happen when disposed or not on a function
}
VisualGraphViewUpdater<FGVertex, FGEdge> updater = viewer.getViewUpdater();
assertNotNull(updater);
return updater;
}
protected void waitForAnimation(FGController controller, FGProvider fgProvider) {
VisualGraphViewUpdater<FGVertex, FGEdge> updater = getGraphUpdater(fgProvider);
if (updater == null) {
return; // nothing to wait for; no active graph
}
// long start = System.nanoTime();
waitForSwing();
int tryCount = 3;
while (tryCount++ < 5 && updater.isBusy()) {
waitForConditionWithoutFailing(() -> !updater.isBusy());
}
waitForSwing();
assertFalse(updater.isBusy());
// long end = System.nanoTime();
// long total = end - start;
// Msg.debug(this,
// "Animation wait time: " + TimeUnit.MILLISECONDS.convert(total, TimeUnit.NANOSECONDS));
}
@SuppressWarnings("rawtypes")
private void setGraphLayout(FGProvider fgProvider) {
long start = System.currentTimeMillis();
Object actionManager = getInstanceField("actionManager", fgProvider);
final MultiStateDockingAction<?> action =
(MultiStateDockingAction<?>) getInstanceField("layoutAction", actionManager);
Object minCrossState = null;
List<?> states = action.getAllActionStates();
for (Object state : states) {
if (((ActionState) state).getName().indexOf("Nested Code Layout") != -1) {
minCrossState = state;
break;
}
}
assertNotNull("Could not find min cross layout!", minCrossState);
//@formatter:off
invokeInstanceMethod( "setCurrentActionState",
action,
new Class<?>[] { ActionState.class },
new Object[] { minCrossState });
//@formatter:on
runSwing(() -> action.actionPerformed(new DefaultActionContext()));
// wait for the threaded graph layout code
FGController controller = getFunctionGraphController(fgProvider);
waitForBusyRunManager(controller);
waitForAnimation(controller, fgProvider);
getPrimaryGraphViewer(fgProvider).repaint();
waitForSwing();
long end = System.currentTimeMillis();
Msg.debug(this, "relayout time: " + ((end - start) / 1000.0) + "s");
}
@Test
public void testCaptureDebuggerFunctionGraphBreakpointMargin() throws Throwable {
mb.createTestModel();
modelService.addModel(mb.testModel);
mb.createTestProcessesAndThreads();
TestDebuggerTargetTraceMapper mapper = new TestDebuggerTargetTraceMapper(mb.testProcess1);
TraceRecorder recorder =
modelService.recordTarget(mb.testProcess1, mapper, ActionSource.AUTOMATIC);
Trace trace = recorder.getTrace();
traceManager.openTrace(trace);
traceManager.activateTrace(trace);
tool.getProject()
.getProjectData()
.getRootFolder()
.createFile("WinHelloCPP", program, TaskMonitor.DUMMY);
try (Transaction tx = trace.openTransaction("Add Mapping")) {
mappingService.addIdentityMapping(trace, program, Lifespan.nowOn(0), true);
}
waitForValue(() -> mappingService.getOpenMappedLocation(
new DefaultTraceLocation(trace, null, Lifespan.at(0), mb.addr(0x00401070))));
Msg.debug(this, "Placing breakpoint");
breakpointService.placeBreakpointAt(program, addr(program, 0x00401070), 1,
Set.of(TraceBreakpointKind.SW_EXECUTE), "");
addPlugin(tool, FunctionGraphPlugin.class);
FGProvider fgProvider = waitForComponentProvider(FGProvider.class);
Swing.runNow(() -> tool.showComponentProvider(fgProvider, true));
setGraphLayout(fgProvider);
goTo(tool, program, addr(program, 0x00401070));
captureIsolatedProvider(fgProvider, 700, 700);
}
@Test
public void testCaptureDebuggerDecompilerBreakpointMargin() throws Throwable {
mb.createTestModel();