GP-2189: Add FlatDebuggerAPI interface

This commit is contained in:
Dan 2022-08-15 15:18:15 -04:00
parent 58066601fc
commit c7b464a0be
46 changed files with 4619 additions and 129 deletions

View file

@ -261,6 +261,10 @@ public class DebuggerCoordinates {
return all(trace, recorder, thread, view, newTime, frame);
}
public DebuggerCoordinates withFrame(int newFrame) {
return all(trace, recorder, thread, view, time, newFrame);
}
public DebuggerCoordinates withView(TraceProgramView newView) {
return all(trace, recorder, thread, newView, time, frame);
}

View file

@ -196,7 +196,8 @@ public class DebuggerStaticSyncTrait {
}
protected void doSyncCursorIntoStatic(ProgramLocation location) {
if (location == null) {
DebuggerStaticMappingService mappingService = this.mappingService;
if (location == null || mappingService == null) {
return;
}
ProgramLocation staticLoc = mappingService.getStaticLocationFromDynamic(location);
@ -207,8 +208,10 @@ public class DebuggerStaticSyncTrait {
}
protected void doSyncCursorFromStatic() {
ProgramLocation currentStaticLocation = this.currentStaticLocation;
TraceProgramView view = current.getView(); // NB. Used for snap (don't want emuSnap)
if (view == null || currentStaticLocation == null) {
DebuggerStaticMappingService mappingService = this.mappingService;
if (currentStaticLocation == null || view == null || mappingService == null) {
return;
}
ProgramLocation dynamicLoc =

View file

@ -18,6 +18,7 @@ package ghidra.app.plugin.core.debug.gui.breakpoint;
import java.awt.Color;
import java.awt.event.KeyEvent;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import javax.swing.SwingUtilities;
@ -861,7 +862,6 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin
}
protected void doToggleBreakpointsAt(String title, ActionContext context) {
// TODO: Seems like this should be in logical breakpoint service?
if (breakpointService == null) {
return;
}
@ -869,39 +869,21 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin
if (loc == null) {
return;
}
Set<LogicalBreakpoint> bs = breakpointService.getBreakpointsAt(loc);
if (bs == null || bs.isEmpty()) {
breakpointService.toggleBreakpointsAt(loc, () -> {
Set<TraceBreakpointKind> supported = getSupportedKindsFromContext(context);
if (supported.isEmpty()) {
breakpointError(title, "It seems this target does not support breakpoints.");
return;
return CompletableFuture.completedFuture(Set.of());
}
Set<TraceBreakpointKind> kinds = computeDefaultKinds(context, supported);
long length = computeDefaultLength(context, kinds);
placeBreakpointDialog.prompt(tool, breakpointService, title, loc, length, kinds, "");
return;
}
State state = breakpointService.computeState(bs, loc);
/**
* If we're in the static listing, this will return null, indicating we should use the
* program's perspective. The methods taking trace should accept a null trace and behave
* accordingly. If in the dynamic listing, we act in the context of the returned trace.
*/
Trace trace = getTraceFromContext(context);
boolean mapped = breakpointService.anyMapped(bs, trace);
State toggled = state.getToggled(mapped);
if (toggled.isEnabled()) {
breakpointService.enableAll(bs, trace).exceptionally(ex -> {
breakpointError(title, "Could not enable breakpoints", ex);
return null;
});
}
else {
breakpointService.disableAll(bs, trace).exceptionally(ex -> {
breakpointError(title, "Could not disable breakpoints", ex);
return null;
});
}
// Not great, but I'm not sticking around for the dialog
return CompletableFuture.completedFuture(Set.of());
}).exceptionally(ex -> {
breakpointError(title, "Could not toggle breakpoints", ex);
return null;
});
}
/**

View file

@ -1492,7 +1492,7 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter
public void performLaunch(ActionContext context) {
performAction(context, true, TargetLauncher.class, launcher -> {
Map<String, ?> args = launchOffer.getLauncherArgs(launcher.getParameters(), true);
Map<String, ?> args = launchOffer.getLauncherArgs(launcher, true);
if (args == null) {
// Cancelled
return AsyncUtils.NIL;

View file

@ -18,8 +18,7 @@ package ghidra.app.plugin.core.debug.service.breakpoint;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.*;
import java.util.stream.Collectors;
import org.apache.commons.collections4.IteratorUtils;
@ -785,7 +784,7 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin
protected void processChange(Consumer<ChangeCollector> processor, String description) {
executor.submit(() -> {
// Issue change callbacks without the lock! (try must surround sync)
// Invoke change callbacks without the lock! (try must surround sync)
try (ChangeCollector c = new ChangeCollector(changeListeners.fire)) {
synchronized (lock) {
processor.accept(c);
@ -1206,6 +1205,29 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin
});
}
@Override
public CompletableFuture<Set<LogicalBreakpoint>> toggleBreakpointsAt(ProgramLocation loc,
Supplier<CompletableFuture<Set<LogicalBreakpoint>>> placer) {
Set<LogicalBreakpoint> bs = getBreakpointsAt(loc);
if (bs == null || bs.isEmpty()) {
return placer.get();
}
State state = computeState(bs, loc);
/**
* If we're in the static listing, this will return null, indicating we should use the
* program's perspective. The methods taking trace should accept a null trace and behave
* accordingly. If in the dynamic listing, we act in the context of the returned trace.
*/
Trace trace =
DebuggerLogicalBreakpointService.programOrTrace(loc, (p, a) -> null, (t, a) -> t);
boolean mapped = anyMapped(bs, trace);
State toggled = state.getToggled(mapped);
if (toggled.isEnabled()) {
return enableAll(bs, trace).thenApply(__ -> bs);
}
return disableAll(bs, trace).thenApply(__ -> bs);
}
@Override
public void processEvent(PluginEvent event) {
if (event instanceof ProgramOpenedPluginEvent) {

View file

@ -87,7 +87,8 @@ public class DebuggerModelServiceProxyPlugin extends Plugin
private static final DebuggerProgramLaunchOffer DUMMY_LAUNCH_OFFER =
new DebuggerProgramLaunchOffer() {
@Override
public CompletableFuture<Void> launchProgram(TaskMonitor monitor, boolean prompt) {
public CompletableFuture<LaunchResult> launchProgram(TaskMonitor monitor,
boolean prompt, LaunchConfigurator configurator) {
throw new AssertionError("Who clicked me?");
}

View file

@ -562,9 +562,13 @@ public class DefaultTraceRecorder implements TraceRecorder {
return true;
}
// UNUSED?
@Override
public CompletableFuture<Void> flushTransactions() {
return parTx.flush();
return CompletableFuture.runAsync(() -> {
}, privateQueue).thenCompose(__ -> {
return objectManager.flushEvents();
}).thenCompose(__ -> {
return parTx.flush();
});
}
}

View file

@ -285,4 +285,8 @@ public class TraceEventListener extends AnnotatedDebuggerAttributeListener {
reorderer.dispose();
}
public CompletableFuture<Void> flushEvents() {
return reorderer.flushEvents();
}
}

View file

@ -220,6 +220,10 @@ public class TraceObjectListener implements DebuggerModelListener {
reorderer.dispose();
}
public CompletableFuture<Void> flushEvents() {
return reorderer.flushEvents();
}
/*
private CompletableFuture<List<TargetObject>> findDependenciesTop(TargetObject added) {
List<TargetObject> result = new ArrayList<>();

View file

@ -702,4 +702,10 @@ public class TraceObjectManager {
objectListener.dispose();
}
public CompletableFuture<Void> flushEvents() {
return eventListener.flushEvents().thenCompose(__ -> {
return objectListener.flushEvents();
});
}
}

View file

@ -23,7 +23,6 @@ import java.util.stream.Collectors;
import javax.swing.JOptionPane;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.jdom.Element;
import org.jdom.JDOMException;
@ -35,6 +34,7 @@ import ghidra.dbg.*;
import ghidra.dbg.target.*;
import ghidra.dbg.target.TargetLauncher.TargetCmdLineLauncher;
import ghidra.dbg.target.TargetMethod.ParameterDescription;
import ghidra.dbg.target.TargetMethod.TargetParameterMap;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.dbg.util.PathUtils;
import ghidra.framework.model.DomainFile;
@ -276,11 +276,14 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg
* @param params the parameters of the model's launcher
* @return the arguments given by the user, or null if cancelled
*/
protected Map<String, ?> promptLauncherArgs(Map<String, ParameterDescription<?>> params) {
protected Map<String, ?> promptLauncherArgs(TargetLauncher launcher,
LaunchConfigurator configurator) {
TargetParameterMap params = launcher.getParameters();
DebuggerMethodInvocationDialog dialog =
new DebuggerMethodInvocationDialog(tool, getButtonTitle(), "Launch", getIcon());
// NB. Do not invoke read/writeConfigState
Map<String, ?> args = loadLastLauncherArgs(params, true);
Map<String, ?> args = configurator.configureLauncher(launcher,
loadLastLauncherArgs(launcher, true), RelPrompt.BEFORE);
for (ParameterDescription<?> param : params.values()) {
Object val = args.get(param.name);
if (val != null) {
@ -311,13 +314,13 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg
* @param forPrompt true if the user will be confirming the arguments
* @return the loaded arguments, or defaults
*/
protected Map<String, ?> loadLastLauncherArgs(
Map<String, ParameterDescription<?>> params, boolean forPrompt) {
protected Map<String, ?> loadLastLauncherArgs(TargetLauncher launcher, boolean forPrompt) {
/**
* TODO: Supposedly, per-program, per-user config stuff is being generalized for analyzers.
* Re-examine this if/when that gets merged
*/
if (program != null) {
TargetParameterMap params = launcher.getParameters();
ProgramUserData userData = program.getProgramUserData();
String property =
userData.getStringProperty(TargetCmdLineLauncher.CMDLINE_ARGS_NAME, null);
@ -354,7 +357,6 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg
}
return new LinkedHashMap<>();
}
/**
@ -368,11 +370,17 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg
* @param params the parameters of the model's launcher
* @return the chosen arguments, or null if the user cancels at the prompt
*/
public Map<String, ?> getLauncherArgs(Map<String, ParameterDescription<?>> params,
boolean prompt) {
public Map<String, ?> getLauncherArgs(TargetLauncher launcher,
boolean prompt, LaunchConfigurator configurator) {
return prompt
? promptLauncherArgs(params)
: loadLastLauncherArgs(params, false);
? configurator.configureLauncher(launcher,
promptLauncherArgs(launcher, configurator), RelPrompt.AFTER)
: configurator.configureLauncher(launcher, loadLastLauncherArgs(launcher, false),
RelPrompt.NONE);
}
public Map<String, ?> getLauncherArgs(TargetLauncher launcher, boolean prompt) {
return getLauncherArgs(launcher, prompt, LaunchConfigurator.NOP);
}
/**
@ -431,8 +439,9 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg
}
protected CompletableFuture<DebuggerObjectModel> connect(DebuggerModelService service,
boolean prompt) {
boolean prompt, LaunchConfigurator configurator) {
DebuggerModelFactory factory = getModelFactory();
configurator.configureConnector(factory);
if (prompt) {
return service.showConnectDialog(factory);
}
@ -454,8 +463,8 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg
// Eww.
protected CompletableFuture<Void> launch(TargetLauncher launcher,
boolean prompt) {
Map<String, ?> args = getLauncherArgs(launcher.getParameters(), prompt);
boolean prompt, LaunchConfigurator configurator) {
Map<String, ?> args = getLauncherArgs(launcher, prompt, configurator);
if (args == null) {
throw new CancellationException();
}
@ -551,17 +560,27 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg
}
@Override
public CompletableFuture<Void> launchProgram(TaskMonitor monitor, boolean prompt) {
public CompletableFuture<LaunchResult> launchProgram(TaskMonitor monitor, boolean prompt,
LaunchConfigurator configurator) {
DebuggerModelService service = tool.getService(DebuggerModelService.class);
DebuggerStaticMappingService mappingService =
tool.getService(DebuggerStaticMappingService.class);
monitor.initialize(6);
monitor.setMessage("Connecting");
var locals = new Object() {
DebuggerObjectModel model;
CompletableFuture<TargetObject> futureTarget;
TargetObject target;
TraceRecorder recorder;
Throwable exception;
LaunchResult getResult() {
return new LaunchResult(model, target, recorder, exception);
}
};
return connect(service, prompt).thenCompose(m -> {
return connect(service, prompt, configurator).thenCompose(m -> {
checkCancelled(monitor);
locals.model = m;
monitor.incrementProgress(1);
monitor.setMessage("Finding Launcher");
return AsyncTimer.DEFAULT_TIMER.mark()
@ -573,7 +592,7 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg
monitor.setMessage("Launching");
locals.futureTarget = listenForTarget(l.getModel());
return AsyncTimer.DEFAULT_TIMER.mark()
.timeOut(launch(l, prompt), getTimeoutMillis(),
.timeOut(launch(l, prompt, configurator), getTimeoutMillis(),
() -> onTimedOutLaunch(monitor));
}).thenCompose(__ -> {
checkCancelled(monitor);
@ -584,6 +603,7 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg
() -> onTimedOutTarget(monitor));
}).thenCompose(t -> {
checkCancelled(monitor);
locals.target = t;
monitor.incrementProgress(1);
monitor.setMessage("Waiting for recorder");
return AsyncTimer.DEFAULT_TIMER.mark()
@ -591,6 +611,7 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg
() -> onTimedOutRecorder(monitor, service, t));
}).thenCompose(r -> {
checkCancelled(monitor);
locals.recorder = r;
monitor.incrementProgress(1);
if (r == null) {
throw new CancellationException();
@ -600,10 +621,16 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg
.timeOut(listenForMapping(mappingService, r), getTimeoutMillis(),
() -> onTimedOutMapping(monitor, mappingService, r));
}).exceptionally(ex -> {
if (AsyncUtils.unwrapThrowable(ex) instanceof CancellationException) {
return null;
locals.exception = AsyncUtils.unwrapThrowable(ex);
return null;
}).thenApply(__ -> {
if (locals.exception != null) {
monitor.setMessage("Launch error: " + locals.exception);
return locals.getResult();
}
return ExceptionUtils.rethrow(ex);
monitor.setMessage("Launch successful");
monitor.incrementProgress(1);
return locals.getResult();
});
}
}

View file

@ -15,11 +15,17 @@
*/
package ghidra.app.plugin.core.debug.service.model.launch;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import javax.swing.Icon;
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
import ghidra.app.services.TraceRecorder;
import ghidra.dbg.DebuggerModelFactory;
import ghidra.dbg.DebuggerObjectModel;
import ghidra.dbg.target.TargetLauncher;
import ghidra.dbg.target.TargetObject;
import ghidra.util.task.TaskMonitor;
/**
@ -32,6 +38,89 @@ import ghidra.util.task.TaskMonitor;
*/
public interface DebuggerProgramLaunchOffer {
/**
* The result of launching a program
*
* <p>
* The launch may not always be completely successful. Instead of tearing things down, partial
* launches are left in place, in case the user wishes to repair/complete the steps manually. If
* the result includes a recorder, the launch was completed successfully. If not, then the
* caller can choose how to treat the connection and target. If the cause of failure was an
* exception, it is included. If the launch succeeded, but module mapping failed, the result
* will include a recorder and the exception.
*
* @param model the connection
* @param target the launched target
* @param recorder the recorder
* @param exception optional error, if failed
*/
public record LaunchResult(DebuggerObjectModel model, TargetObject target,
TraceRecorder recorder, Throwable exception) {
public static LaunchResult totalFailure(Throwable ex) {
return new LaunchResult(null, null, null, ex);
}
}
/**
* When programmatically customizing launch configuration, describes callback timing relative to
* prompting the user.
*/
public enum RelPrompt {
/**
* The user is not prompted for parameters. This will be the only callback.
*/
NONE,
/**
* The user will be prompted. This callback can pre-populate suggested parameters. Another
* callback will be issued if the user does not cancel.
*/
BEFORE,
/**
* The user has confirmed the parameters. This callback can validate or override the users
* parameters. Overriding the user is discouraged. This is the final callback.
*/
AFTER;
}
/**
* Callbacks for custom configuration when launching a program
*/
public interface LaunchConfigurator {
LaunchConfigurator NOP = new LaunchConfigurator() {};
/**
* Re-configure the factory, if desired
*
* @param factory the factory that will create the connection
*/
default void configureConnector(DebuggerModelFactory factory) {
}
/**
* Re-write the launcher arguments, if desired
*
* @param launcher the launcher that will create the target
* @param arguments the arguments suggested by the offer or saved settings
* @param relPrompt describes the timing of this callback relative to prompting the user
* @return the adjusted arguments
*/
default Map<String, ?> configureLauncher(TargetLauncher launcher,
Map<String, ?> arguments, RelPrompt relPrompt) {
return arguments;
}
}
/**
* Launch the program using the offered mechanism
*
* @param monitor a monitor for progress and cancellation
* @param prompt if the user should be prompted to confirm launch parameters
* @param configurator the configuration callbacks
* @return a future which completes when the program is launched
*/
CompletableFuture<LaunchResult> launchProgram(TaskMonitor monitor, boolean prompt,
LaunchConfigurator configurator);
/**
* Launch the program using the offered mechanism
*
@ -39,7 +128,9 @@ public interface DebuggerProgramLaunchOffer {
* @param prompt if the user should be prompted to confirm launch parameters
* @return a future which completes when the program is launched
*/
CompletableFuture<Void> launchProgram(TaskMonitor monitor, boolean prompt);
default CompletableFuture<LaunchResult> launchProgram(TaskMonitor monitor, boolean prompt) {
return launchProgram(monitor, prompt, LaunchConfigurator.NOP);
}
/**
* A name so that this offer can be recognized later

View file

@ -599,7 +599,7 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
@Override
public CompletableFuture<Void> changesSettled() {
return changeDebouncer.settled();
return changeDebouncer.stable();
}
@Override

View file

@ -18,6 +18,7 @@ package ghidra.app.services;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import ghidra.app.plugin.core.debug.service.breakpoint.DebuggerLogicalBreakpointServicePlugin;
import ghidra.app.services.LogicalBreakpoint.State;
@ -351,4 +352,14 @@ public interface DebuggerLogicalBreakpointService {
* @return a future which completes when the command has been processed
*/
CompletableFuture<Void> deleteLocs(Collection<TraceBreakpoint> col);
/**
* Toggle the breakpoints at the given location
*
* @param location the location
* @param placer if there are no breakpoints, a routine for placing a breakpoint
* @return a future which completes when the command has been processed
*/
CompletableFuture<Set<LogicalBreakpoint>> toggleBreakpointsAt(ProgramLocation location,
Supplier<CompletableFuture<Set<LogicalBreakpoint>>> placer);
}

View file

@ -742,12 +742,13 @@ public interface LogicalBreakpoint {
* Enable (or create) this breakpoint in the given target.
*
* <p>
* Presuming the breakpoint is mappable to the given trace, if no breakpoint of the same kind
* exists at the mapped address, then this will create a new breakpoint. Note, depending on the
* debugging model, the enabled or created breakpoint may apply to more than the given trace.
* If the breakpoint already exists, it is enabled. If it's already enabled, this has no effect.
* If not, and the breakpoint is mappable to the given trace, the breakpoint is created. Note,
* depending on the debugging model, the enabled or created breakpoint may affect other targets.
* If the breakpoint is not mappable to the given trace, this has no effect.
*
* <p>
* This simply issues the command. The logical breakpoint is updated only when the resulting
* This simply issues the command(s). The logical breakpoint is updated only when the resulting
* events are processed.
*
* @param trace the trace for the given target
@ -761,7 +762,7 @@ public interface LogicalBreakpoint {
* <p>
* Note this will not create any new breakpoints. It will disable all breakpoints of the same
* kind at the mapped address. Note, depending on the debugging model, the disabled breakpoint
* may apply to more than the given trace.
* may affect other targets.
*
* <p>
* This simply issues the command. The logical breakpoint is updated only when the resulting
@ -779,7 +780,7 @@ public interface LogicalBreakpoint {
* This presumes the breakpoint's specifications are deletable. Note that if the logical
* breakpoint is still mappable into this trace, a marker may be displayed, even though no
* breakpoint is actually present. Note, depending on the debugging model, the deleted
* breakpoint may be removed from more than the given trace.
* breakpoint may be removed from other targets.
*
* This simply issues the command. The logical breakpoint is updated only when the resulting
* events are processed.
@ -794,7 +795,7 @@ public interface LogicalBreakpoint {
*
* <p>
* This affects the mapped program, if applicable, and all open and live traces. Note, depending
* on the debugging model, the enabled or created breakpoints may apply to more targets.
* on the debugging model, the enabled or created breakpoints may affect other targets.
*
* <p>
* This simply issues the command. The logical breakpoint is updated only when the resulting
@ -809,7 +810,7 @@ public interface LogicalBreakpoint {
*
* <p>
* This affects the mapped program, if applicable, and all open and live traces. Note, depending
* on the debugging model, the disabled breakpoints may apply to more targets.
* on the debugging model, the disabled breakpoints may affect other targets.
*
* <p>
* This simply issues the command. The logical breakpoint is updated only when the resulting
@ -825,7 +826,7 @@ public interface LogicalBreakpoint {
* <p>
* This presumes the breakpoint's specifications are deletable. This affects the mapped program,
* if applicable, and all open and live traces. Note, depending on the debugging model, the
* deleted breakpoints may be removed from more targets.
* deleted breakpoints may be removed from other targets.
*
* <p>
* This simply issues the command. The logical breakpoint is updated only when the resulting

File diff suppressed because it is too large Load diff

View file

@ -25,7 +25,6 @@ import generic.Unique;
import ghidra.app.plugin.core.debug.service.model.launch.DebuggerProgramLaunchOffer;
import ghidra.app.plugin.core.debug.service.model.launch.DebuggerProgramLaunchOpinion;
import ghidra.app.services.DebuggerModelService;
import ghidra.async.AsyncUtils;
import ghidra.dbg.DebuggerModelFactory;
import ghidra.dbg.model.TestDebuggerModelFactory;
import ghidra.framework.plugintool.PluginTool;
@ -34,10 +33,12 @@ import ghidra.util.task.TaskMonitor;
public class TestDebuggerProgramLaunchOpinion implements DebuggerProgramLaunchOpinion {
static class TestDebuggerProgramLaunchOffer implements DebuggerProgramLaunchOffer {
public static class TestDebuggerProgramLaunchOffer implements DebuggerProgramLaunchOffer {
@Override
public CompletableFuture<Void> launchProgram(TaskMonitor monitor, boolean prompt) {
return AsyncUtils.NIL;
public CompletableFuture<LaunchResult> launchProgram(TaskMonitor monitor, boolean prompt,
LaunchConfigurator configurator) {
return CompletableFuture
.completedFuture(LaunchResult.totalFailure(new AssertionError()));
}
@Override

View file

@ -15,7 +15,7 @@
*/
package ghidra.app.plugin.core.debug.service.model.record;
import static org.hamcrest.Matchers.isOneOf;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.math.BigInteger;
@ -304,7 +304,7 @@ public class ObjectBasedTraceRecorderTest extends AbstractGhidraHeadedDebuggerGU
mb.testProcess1.memory.setMemory(tb.addr(0x00400123), mb.arr(1, 2, 3, 4, 5, 6, 7, 8, 9));
flushAndWait();
assertThat(memory.getState(recorder.getSnap(), tb.addr(0x00400123)),
isOneOf(null, TraceMemoryState.UNKNOWN));
is(oneOf(null, TraceMemoryState.UNKNOWN)));
byte[] data = new byte[10];
waitOn(recorder.readMemory(tb.addr(0x00400123), 10));
@ -331,7 +331,7 @@ public class ObjectBasedTraceRecorderTest extends AbstractGhidraHeadedDebuggerGU
mb.testProcess1.memory.setMemory(tb.addr(0x00400123), mb.arr(1, 2, 3, 4, 5, 6, 7, 8, 9));
flushAndWait();
assertThat(memory.getState(recorder.getSnap(), tb.addr(0x00400123)),
isOneOf(null, TraceMemoryState.UNKNOWN));
is(oneOf(null, TraceMemoryState.UNKNOWN)));
byte[] data = new byte[10];
assertNull(waitOn(recorder.readMemoryBlocks(
@ -354,7 +354,7 @@ public class ObjectBasedTraceRecorderTest extends AbstractGhidraHeadedDebuggerGU
mb.testProcess1.memory.addRegion("exe:.text", mb.rng(0x00400000, 0x00400fff), "rwx");
flushAndWait();
assertThat(memory.getState(recorder.getSnap(), tb.addr(0x00400123)),
isOneOf(null, TraceMemoryState.UNKNOWN));
is(oneOf(null, TraceMemoryState.UNKNOWN)));
byte[] data = new byte[10];
waitOn(recorder.writeMemory(tb.addr(0x00400123), tb.arr(1, 2, 3, 4, 5, 6, 7, 8, 9)));

File diff suppressed because it is too large Load diff