GP-3837: Update Debugger Help for Trace RMI.

This commit is contained in:
Dan 2024-04-12 16:39:41 -04:00
parent 6c60bd0313
commit c634283544
134 changed files with 3214 additions and 1550 deletions

View file

@ -15,37 +15,43 @@
*/
package ghidra.app.plugin.core.debug.gui.breakpoint;
import static ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerTest.*;
import static org.junit.Assert.*;
import static ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerTest.waitForPass;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import java.util.List;
import java.util.Set;
import org.junit.*;
import db.Transaction;
import generic.Unique;
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerTest.TestDebuggerTargetTraceMapper;
import ghidra.app.plugin.core.debug.service.breakpoint.DebuggerLogicalBreakpointServicePlugin;
import ghidra.app.plugin.core.debug.service.model.DebuggerModelServiceProxyPlugin;
import ghidra.app.plugin.core.debug.service.control.MockTarget;
import ghidra.app.plugin.core.debug.service.emulation.ProgramEmulationUtils;
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin;
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingUtils;
import ghidra.app.plugin.core.debug.service.target.DebuggerTargetServicePlugin;
import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin;
import ghidra.app.plugin.core.progmgr.ProgramManagerPlugin;
import ghidra.app.services.*;
import ghidra.dbg.model.TestDebuggerModelBuilder;
import ghidra.dbg.target.TargetBreakpointSpec.TargetBreakpointKind;
import ghidra.dbg.target.TargetBreakpointSpecContainer;
import ghidra.dbg.target.TargetTogglable;
import ghidra.dbg.testutil.DebuggerModelTestUtils;
import ghidra.debug.api.action.ActionSource;
import ghidra.debug.api.breakpoint.LogicalBreakpoint;
import ghidra.debug.api.model.TraceRecorder;
import ghidra.framework.model.DomainFolder;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ProgramLocation;
import ghidra.test.ToyProgramBuilder;
import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.database.breakpoint.DBTraceBreakpointManager;
import ghidra.trace.model.*;
import ghidra.trace.model.breakpoint.TraceBreakpoint;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.target.TraceObjectKeyPath;
import ghidra.util.Msg;
import ghidra.util.task.TaskMonitor;
import help.screenshot.GhidraScreenShotGenerator;
@ -53,8 +59,7 @@ import help.screenshot.GhidraScreenShotGenerator;
public class DebuggerBreakpointsPluginScreenShots extends GhidraScreenShotGenerator
implements DebuggerModelTestUtils {
TestDebuggerModelBuilder mb = new TestDebuggerModelBuilder();
DebuggerModelServiceProxyPlugin modelService;
DebuggerTargetService targetService;
DebuggerStaticMappingService mappingService;
DebuggerLogicalBreakpointService breakpointService;
DebuggerTraceManagerService traceManager;
@ -73,7 +78,7 @@ public class DebuggerBreakpointsPluginScreenShots extends GhidraScreenShotGenera
@Before
public void setUpMine() throws Exception {
breakpointService = addPlugin(tool, DebuggerLogicalBreakpointServicePlugin.class);
modelService = addPlugin(tool, DebuggerModelServiceProxyPlugin.class);
targetService = addPlugin(tool, DebuggerTargetServicePlugin.class);
mappingService = addPlugin(tool, DebuggerStaticMappingServicePlugin.class);
traceManager = addPlugin(tool, DebuggerTraceManagerServicePlugin.class);
programManager = addPlugin(tool, ProgramManagerPlugin.class);
@ -110,80 +115,85 @@ public class DebuggerBreakpointsPluginScreenShots extends GhidraScreenShotGenera
DebuggerBreakpointsProvider provider =
waitForComponentProvider(DebuggerBreakpointsProvider.class);
mb.createTestModel();
modelService.addModel(mb.testModel);
mb.createTestProcessesAndThreads();
try (
ToyDBTraceBuilder tb1 =
new ToyDBTraceBuilder("echo.1", ProgramBuilder._TOY64_BE);
ToyDBTraceBuilder tb2 =
new ToyDBTraceBuilder("echo.2", ProgramBuilder._TOY64_BE);) {
TraceRecorder recorder1 = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1), ActionSource.AUTOMATIC);
TraceRecorder recorder3 = modelService.recordTarget(mb.testProcess3,
new TestDebuggerTargetTraceMapper(mb.testProcess3), ActionSource.AUTOMATIC);
Trace trace1 = recorder1.getTrace();
Trace trace3 = recorder3.getTrace();
targetService.publishTarget(new MockTarget(tb1.trace));
targetService.publishTarget(new MockTarget(tb2.trace));
DomainFolder root = tool.getProject().getProjectData().getRootFolder();
root.createFile("echo.1", tb1.trace, TaskMonitor.DUMMY);
root.createFile("echo.2", tb2.trace, TaskMonitor.DUMMY);
programManager.openProgram(program);
traceManager.openTrace(trace1);
traceManager.openTrace(trace3);
try (Transaction tx = tb1.startTransaction()) {
DebuggerStaticMappingUtils.addMapping(
new DefaultTraceLocation(tb1.trace, null, Lifespan.nowOn(0),
addr(tb1.trace, 0x00400000)),
new ProgramLocation(program, addr(program, 0x00400000)), 0x00210000, false);
}
try (Transaction tx = tb2.startTransaction()) {
DebuggerStaticMappingUtils.addMapping(
new DefaultTraceLocation(tb2.trace, null, Lifespan.nowOn(0),
addr(tb2.trace, 0x7fac0000)),
new ProgramLocation(program, addr(program, 0x00400000)), 0x00010000, false);
}
waitForSwing();
mb.testProcess1.addRegion("echo:.text", mb.rng(0x00400000, 0x00400fff), "rx");
mb.testProcess1.addRegion("echo:.data", mb.rng(0x00600000, 0x00600fff), "rw");
mb.testProcess3.addRegion("echo:.text", mb.rng(0x7fac0000, 0x7fac0fff), "rx");
try (Transaction tx = program.openTransaction("Add breakpoint")) {
program.getBookmarkManager()
.setBookmark(addr(program, 0x00401234),
LogicalBreakpoint.ENABLED_BOOKMARK_TYPE,
"SW_EXECUTE;1", "before connect");
program.getBookmarkManager()
.setBookmark(addr(program, 0x00604321),
LogicalBreakpoint.ENABLED_BOOKMARK_TYPE,
"WRITE;4", "write version");
}
try (Transaction tx = trace1.openTransaction("Add mapping")) {
DebuggerStaticMappingUtils.addMapping(
new DefaultTraceLocation(trace1, null, Lifespan.nowOn(0), addr(trace1, 0x00400000)),
new ProgramLocation(program, addr(program, 0x00400000)), 0x00210000, false);
try (Transaction tx = tb1.startTransaction()) {
tb1.trace.getObjectManager()
.createRootObject(ProgramEmulationUtils.EMU_SESSION_SCHEMA);
long snap = tb1.trace.getTimeManager().createSnapshot("First").getKey();
DBTraceBreakpointManager bm = tb1.trace.getBreakpointManager();
bm.placeBreakpoint("Breakpoints[1]", snap, tb1.addr(0x00401234), List.of(),
Set.of(TraceBreakpointKind.SW_EXECUTE), true, "ram:00401234");
bm.placeBreakpoint("Breakpoints[2]", snap, tb1.range(0x00604321, 0x00604324),
List.of(),
Set.of(TraceBreakpointKind.WRITE), true, "ram:00604321");
}
try (Transaction tx = tb2.startTransaction()) {
tb2.trace.getObjectManager()
.createRootObject(ProgramEmulationUtils.EMU_SESSION_SCHEMA);
long snap = tb2.trace.getTimeManager().createSnapshot("First").getKey();
DBTraceBreakpointManager bm = tb2.trace.getBreakpointManager();
bm.placeBreakpoint("Breakpoints[1]", snap, tb2.addr(0x7fac1234), List.of(),
Set.of(TraceBreakpointKind.SW_EXECUTE), false, "ram:7fac1234");
}
programManager.openProgram(program);
traceManager.openTrace(tb1.trace);
traceManager.openTrace(tb2.trace);
waitForPass(() -> {
Set<LogicalBreakpoint> allBreakpoints = breakpointService.getAllBreakpoints();
assertEquals(2, allBreakpoints.size());
});
/**
* TODO: Might be necessary to debounce and wait for service callbacks to settle.
* Sometimes, there are 3 for just a moment, and then additional callbacks mess things
* up.
*/
waitForPass(() -> {
assertEquals(2, provider.breakpointTable.getRowCount());
assertEquals(3, provider.locationTable.getRowCount());
});
captureIsolatedProvider(provider, 600, 600);
}
try (Transaction tx = trace3.openTransaction("Add mapping")) {
DebuggerStaticMappingUtils.addMapping(
new DefaultTraceLocation(trace3, null, Lifespan.nowOn(0), addr(trace3, 0x7fac0000)),
new ProgramLocation(program, addr(program, 0x00400000)), 0x00010000, false);
}
waitForSwing();
try (Transaction tx = program.openTransaction("Add breakpoint")) {
program.getBookmarkManager()
.setBookmark(addr(program, 0x00401234), LogicalBreakpoint.ENABLED_BOOKMARK_TYPE,
"SW_EXECUTE;1", "before connect");
program.getBookmarkManager()
.setBookmark(addr(program, 0x00604321), LogicalBreakpoint.ENABLED_BOOKMARK_TYPE,
"WRITE;4", "write version");
}
TargetBreakpointSpecContainer bc1 =
waitFor(() -> Unique.assertAtMostOne(recorder1.collectBreakpointContainers(null)),
"No container");
waitOn(bc1.placeBreakpoint(mb.addr(0x00401234), Set.of(TargetBreakpointKind.SW_EXECUTE)));
waitOn(bc1.placeBreakpoint(mb.rng(0x00604321, 0x00604324),
Set.of(TargetBreakpointKind.WRITE)));
TargetBreakpointSpecContainer bc3 =
waitFor(() -> Unique.assertAtMostOne(recorder3.collectBreakpointContainers(null)),
"No container");
waitOn(bc3.placeBreakpoint(mb.addr(0x7fac1234), Set.of(TargetBreakpointKind.SW_EXECUTE)));
TargetTogglable bp3 = (TargetTogglable) waitForValue(
() -> Unique.assertAtMostOne(bc3.getCachedElements().values()));
waitOn(bp3.disable());
TraceBreakpoint bpt = waitForValue(() -> Unique.assertAtMostOne(
trace3.getBreakpointManager()
.getBreakpointsAt(recorder3.getSnap(), addr(trace3, 0x7fac1234))));
waitForPass(() -> {
Set<LogicalBreakpoint> allBreakpoints = breakpointService.getAllBreakpoints();
assertEquals(2, allBreakpoints.size());
});
waitForPass(() -> {
assertFalse(bpt.isEnabled(0));
});
/**
* TODO: Might be necessary to debounce and wait for service callbacks to settle. Sometimes,
* there are 3 for just a moment, and then additional callbacks mess things up.
*/
waitForPass(() -> {
assertEquals(2, provider.breakpointTable.getRowCount());
assertEquals(3, provider.locationTable.getRowCount());
});
captureIsolatedProvider(provider, 600, 600);
}
}

View file

@ -0,0 +1,69 @@
/* ###
* 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.app.plugin.core.debug.gui.tracermi.launcher;
import java.util.Map;
import org.junit.Test;
import ghidra.app.plugin.core.debug.gui.objects.components.DebuggerMethodInvocationDialog;
import ghidra.app.plugin.core.terminal.TerminalProvider;
import ghidra.debug.api.tracermi.TraceRmiLaunchOffer;
import ghidra.test.ToyProgramBuilder;
import help.screenshot.GhidraScreenShotGenerator;
public class TraceRmiLauncherServicePluginScreenShots extends GhidraScreenShotGenerator {
TraceRmiLauncherServicePlugin servicePlugin;
protected void captureLauncherByTitle(String title, Map<String, ?> args) throws Throwable {
servicePlugin = addPlugin(tool, TraceRmiLauncherServicePlugin.class);
ToyProgramBuilder pb = new ToyProgramBuilder("demo", false);
TraceRmiLaunchOffer offer = servicePlugin.getOffers(pb.getProgram())
.stream()
.filter(o -> title.equals(o.getTitle()))
.findAny()
.orElseThrow();
AbstractTraceRmiLaunchOffer aoff = (AbstractTraceRmiLaunchOffer) offer;
aoff.saveLauncherArgs(args, aoff.getParameters());
runSwingLater(() -> servicePlugin.configureAndLaunch(offer));
captureDialog(DebuggerMethodInvocationDialog.class);
}
@Test
public void testCaptureGdbLauncher() throws Throwable {
captureLauncherByTitle("gdb", Map.of("arg:1", "/home/user/demo"));
}
@Test
public void testCaptureGdbTerminal() throws Throwable {
servicePlugin = addPlugin(tool, TraceRmiLauncherServicePlugin.class);
TraceRmiLaunchOffer offer = servicePlugin.getOffers(null)
.stream()
.filter(o -> "raw gdb".equals(o.getTitle()))
.findAny()
.orElseThrow();
servicePlugin.relaunch(offer);
captureIsolatedProvider(TerminalProvider.class, 600, 600);
}
}