GP-704: Converting models to a push-centric comm pattern.

This commit is contained in:
Dan
2021-02-23 10:57:51 -05:00
parent dd37995833
commit 5bb6f95a84
95 changed files with 2348 additions and 1635 deletions

View File

@@ -47,27 +47,33 @@ public abstract class AbstractDebuggerWrappedConsoleConnection<T extends TargetO
*/
protected class ForInterpreterListener implements TargetInterpreterListener {
@Override
public void consoleOutput(TargetObject console, Channel channel, String out) {
// NB: yes, this is lame... The InterpreterPanel's repositionScrollPane
// method substracts 1 from the text length to compute the new position
// causing it to scroll to the last character printed. We want it to scroll
// to the next line, so...
out += " ";
public void consoleOutput(TargetObject console, Channel channel, byte[] out) {
OutputStream os;
switch (channel) {
case STDOUT:
if (outWriter == null) {
return;
}
outWriter.print(out);
outWriter.flush();
os = stdOut;
break;
case STDERR:
if (errWriter == null) {
return;
}
errWriter.print(out);
errWriter.flush();
os = stdErr;
break;
default:
throw new AssertionError();
}
// It's possible stdOut/Err was not initialized, yet
if (os == null) {
return;
}
/**
* NB: yes, the extra space is lame... The InterpreterPanel's repositionScrollPane
* method subtracts 1 from the text length to compute the new position causing it to
* scroll to the last character printed. We want it to scroll to the next line, so...
*/
try {
os.write(out);
os.write(' ');
}
catch (IOException e) {
Msg.error(this, "Cannot write to interpreter window: ", e);
}
}
@@ -84,7 +90,7 @@ public abstract class AbstractDebuggerWrappedConsoleConnection<T extends TargetO
}
@Override
public void invalidated(TargetObject object, String reason) {
public void invalidated(TargetObject object, TargetObject branch, String reason) {
Swing.runLater(() -> {
if (object == targetConsole) { // Redundant
if (pinned) {
@@ -107,8 +113,8 @@ public abstract class AbstractDebuggerWrappedConsoleConnection<T extends TargetO
protected Thread thread;
protected InterpreterConsole guiConsole;
protected BufferedReader inReader;
protected PrintWriter outWriter;
protected PrintWriter errWriter;
protected OutputStream stdOut;
protected OutputStream stdErr;
protected ToggleDockingAction actionPin;
protected boolean pinned = false;
@@ -146,8 +152,8 @@ public abstract class AbstractDebuggerWrappedConsoleConnection<T extends TargetO
InterpreterComponentProvider provider = (InterpreterComponentProvider) guiConsole;
provider.setSubTitle(targetConsole.getDisplay());
setErrWriter(guiConsole.getErrWriter());
setOutWriter(guiConsole.getOutWriter());
setStdErr(guiConsole.getStdErr());
setStdOut(guiConsole.getStdOut());
setStdIn(guiConsole.getStdin());
createActions();
@@ -161,12 +167,12 @@ public abstract class AbstractDebuggerWrappedConsoleConnection<T extends TargetO
guiConsole.addAction(actionPin);
}
public void setOutWriter(PrintWriter outWriter) {
this.outWriter = outWriter;
public void setStdOut(OutputStream stdOut) {
this.stdOut = stdOut;
}
public void setErrWriter(PrintWriter errWriter) {
this.errWriter = errWriter;
public void setStdErr(OutputStream stdErr) {
this.stdErr = stdErr;
}
public void setStdIn(InputStream stdIn) {

View File

@@ -46,22 +46,15 @@ import ghidra.app.plugin.core.debug.gui.objects.components.*;
import ghidra.app.services.*;
import ghidra.async.AsyncUtils;
import ghidra.async.TypeSpec;
import ghidra.dbg.DebugModelConventions;
import ghidra.dbg.DebuggerObjectModel;
import ghidra.dbg.*;
import ghidra.dbg.attributes.TargetObjectRef;
import ghidra.dbg.error.DebuggerMemoryAccessException;
import ghidra.dbg.target.*;
import ghidra.dbg.target.TargetAccessConditioned.TargetAccessibility;
import ghidra.dbg.target.TargetAccessConditioned.TargetAccessibilityListener;
import ghidra.dbg.target.TargetConsole.Channel;
import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState;
import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionStateListener;
import ghidra.dbg.target.TargetFocusScope.TargetFocusScopeListener;
import ghidra.dbg.target.TargetInterpreter.TargetInterpreterListener;
import ghidra.dbg.target.TargetLauncher.TargetCmdLineLauncher;
import ghidra.dbg.target.TargetMemory.TargetMemoryListener;
import ghidra.dbg.target.TargetObject.TargetObjectFetchingListener;
import ghidra.dbg.target.TargetRegisterBank.TargetRegisterBankListener;
import ghidra.dbg.target.TargetSteppable.TargetStepKind;
import ghidra.dbg.util.PathUtils;
import ghidra.framework.options.AutoOptions;
@@ -80,9 +73,9 @@ import ghidra.util.table.GhidraTable;
import resources.ResourceManager;
public class DebuggerObjectsProvider extends ComponentProviderAdapter implements //AllTargetObjectListenerAdapter,
TargetObjectFetchingListener, TargetAccessibilityListener, TargetExecutionStateListener,
TargetFocusScopeListener, TargetInterpreterListener, TargetMemoryListener,
TargetRegisterBankListener, ObjectContainerListener {
TargetObjectFetchingListener, //
DebuggerModelListener, //
ObjectContainerListener {
public static final String PATH_JOIN_CHAR = ".";
//private static final String AUTOUPDATE_ATTRIBUTE_NAME = "autoupdate";
@@ -310,6 +303,7 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter implements
public void setModel(DebuggerObjectModel model) {
currentModel = model;
currentModel.addModelListener(this, true);
refresh();
}
@@ -1384,14 +1378,6 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter implements
});
}
public void addListener(TargetObject targetObject) {
/*
if (recorder != null) {
recorder.getListenerForRecord().addListener(targetObject);
}
*/
}
public void stopRecording(TargetObject targetObject) {
// TODO: Do `this.recorder = ...` on every object selection change?
TraceRecorder rec = modelService.getRecorderForSuccessor(targetObject);
@@ -1681,7 +1667,7 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter implements
public void elementsChangedObjects(TargetObject parent, Collection<String> removed,
Map<String, ? extends TargetObject> added) {
//System.err.println("local EC: " + parent);
ObjectContainer container = getContainerByPath(parent.getPath());
ObjectContainer container = parent == null ? null : getContainerByPath(parent.getPath());
if (container != null) {
container.augmentElements(removed, added);
boolean visibleChange = false;
@@ -1702,7 +1688,7 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter implements
public void attributesChangedObjects(TargetObject parent, Collection<String> removed,
Map<String, ?> added) {
//System.err.println("local AC: " + parent + ":" + removed + ":" + added);
ObjectContainer container = getContainerByPath(parent.getPath());
ObjectContainer container = parent == null ? null : getContainerByPath(parent.getPath());
if (container != null) {
container.augmentAttributes(removed, added);
boolean visibleChange = false;

View File

@@ -15,23 +15,17 @@
*/
package ghidra.app.plugin.core.debug.gui.objects;
import static ghidra.async.AsyncUtils.*;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
import org.jdom.Element;
import ghidra.async.AsyncFence;
import ghidra.async.TypeSpec;
import ghidra.dbg.DebugModelConventions;
import ghidra.dbg.attributes.TargetObjectRef;
import ghidra.dbg.target.TargetObject;
import ghidra.dbg.target.TargetProcess;
import ghidra.dbg.util.PathUtils;
import ghidra.util.Msg;
import ghidra.util.datastruct.ListenerSet;
import ghidra.util.xml.XmlUtilities;
public class ObjectContainer implements Comparable {
@@ -43,9 +37,6 @@ public class ObjectContainer implements Comparable {
private final Map<String, Object> attributeMap = new LinkedHashMap<>();
private Set<ObjectContainer> currentChildren = new TreeSet<>();
public final ListenerSet<ObjectContainerListener> listeners =
new ListenerSet<>(ObjectContainerListener.class);
private boolean immutable;
private boolean visible = true;
private boolean isSubscribed = false;
@@ -171,29 +162,14 @@ public class ObjectContainer implements Comparable {
*/
public CompletableFuture<ObjectContainer> getOffspring() {
if (targetObjectRef == null) {
return null;
if (targetObject == null) {
return CompletableFuture.completedFuture(null);
}
AtomicReference<TargetObject> to = new AtomicReference<>();
AtomicReference<Map<String, ? extends TargetObject>> elements = new AtomicReference<>();
AtomicReference<Map<String, ?>> attributes = new AtomicReference<>();
return sequence(TypeSpec.cls(ObjectContainer.class)).then(seq -> {
targetObjectRef.fetch().handle(seq::next);
}, to).then(seq -> {
targetObject = to.get();
AsyncFence fence = new AsyncFence();
fence.include(targetObject.fetchElements(true)
.thenCompose(DebugModelConventions::fetchAll)
.thenAccept(elements::set));
fence.include(targetObject.fetchAttributes(true)
.thenCompose(attrs -> DebugModelConventions.fetchObjAttrs(targetObject, attrs))
.thenAccept(attributes::set));
fence.ready().handle(seq::next);
}).then(seq -> {
rebuildContainers(elements.get(), attributes.get());
return targetObject.resync(true, true).thenApply(__ -> {
rebuildContainers(targetObject.getCachedElements(), targetObject.getCachedAttributes());
propagateProvider(provider);
seq.exit(this);
}).finish();
return this;
});
}
protected void checkAutoRecord() {
@@ -375,10 +351,6 @@ public class ObjectContainer implements Comparable {
this.provider = newProvider;
provider.addTargetToMap(this);
}
this.addListener(provider);
//if (targetObject != null && !currentChildren.isEmpty()) {
// targetObject.addListener(provider);
//}
for (ObjectContainer c : currentChildren) {
c.propagateProvider(provider);
}
@@ -534,14 +506,6 @@ public class ObjectContainer implements Comparable {
this.immutable = immutable;
}
public void addListener(ObjectContainerListener listener) {
listeners.add(listener);
}
public void removeListener(ObjectContainerListener listener) {
listeners.remove(listener);
}
public boolean isVisible() {
return visible;
}
@@ -561,18 +525,10 @@ public class ObjectContainer implements Comparable {
public void subscribe() {
isSubscribed = true;
if (targetObject != null && provider != null) {
targetObject.addListener(provider);
provider.addListener(targetObject);
}
}
public void unsubscribe() {
isSubscribed = false;
targetObject.removeListener(provider);
if (provider.isAutorecord()) {
//provider.stopRecording(targetObject);
}
}
public boolean isModified() {

View File

@@ -127,7 +127,6 @@ public class ImportFromFactsAction extends ImportExportAsAction {
if (root != null) {
ObjectContainer c = p.getRoot();
c.setTargetObject(root);
root.addListener(p);
provider.update(c);
}
}

View File

@@ -87,7 +87,6 @@ public class ImportFromXMLAction extends ImportExportAsAction {
DummyTargetObject to = xmlToObject(p, root, path);
ObjectContainer c = p.getRoot();
c.setTargetObject(to);
to.addListener(p);
provider.update(c);
}
catch (Exception e) {

View File

@@ -20,6 +20,7 @@ import java.util.concurrent.CompletableFuture;
import org.apache.commons.lang3.StringUtils;
import ghidra.async.AsyncUtils;
import ghidra.dbg.DebuggerObjectModel;
import ghidra.dbg.attributes.TargetObjectRef;
import ghidra.dbg.target.TargetObject;
@@ -156,6 +157,11 @@ public class DummyTargetObject implements TargetObject {
return kind;
}
@Override
public CompletableFuture<Void> resync(boolean attributes, boolean elements) {
return AsyncUtils.NIL;
}
@Override
public CompletableFuture<? extends Map<String, ? extends TargetObject>> fetchElements() {
// Why not completedFuture(elements)?

View File

@@ -34,7 +34,6 @@ public class ObjectAttributeRow {
ref.fetch().handle(seq::next);
}, targetObject).then(seq -> {
to = targetObject.get();
to.addListener(provider);
}).finish();
}

View File

@@ -38,17 +38,10 @@ public class ObjectElementRow {
ref.fetch().handle(seq::next);
}, targetObject).then(seq -> {
to = targetObject.get();
to.addListener(provider);
to.fetchAttributes(true).handle(seq::next);
//to.getAttributes().thenAccept(v -> map = v);
}, attributes).then(seq -> {
map = attributes.get();
for (Object obj : map.values()) {
if (obj instanceof TargetObject) {
TargetObject attr = (TargetObject) obj;
attr.addListener(provider);
}
}
}).finish();
}

View File

@@ -86,7 +86,7 @@ public class DebuggerModelServicePlugin extends Plugin
protected TargetObjectListener forRemoval = new TargetObjectListener() {
@Override
public void invalidated(TargetObject object, String reason) {
public void invalidated(TargetObject object, TargetObject branch, String reason) {
synchronized (listenersByModel) {
ListenersForRemovalAndFocus listener = listenersByModel.remove(model);
if (listener == null) {
@@ -125,7 +125,7 @@ public class DebuggerModelServicePlugin extends Plugin
}
r.addListener(this.forRemoval);
if (!r.isValid()) {
forRemoval.invalidated(root, "Who knows?");
forRemoval.invalidated(root, root, "Who knows?");
}
CompletableFuture<? extends TargetFocusScope<?>> findSuitable =
DebugModelConventions.findSuitable(TargetFocusScope.tclass, r);

View File

@@ -23,7 +23,6 @@ import org.junit.Test;
import ghidra.app.plugin.core.debug.service.model.DebuggerModelServiceInternal;
import ghidra.app.plugin.core.debug.service.model.DebuggerModelServiceProxyPlugin;
import ghidra.async.AsyncUtils;
import ghidra.dbg.DebuggerModelFactory;
import ghidra.dbg.DebuggerObjectModel;
import ghidra.dbg.agent.AbstractDebuggerObjectModel;
@@ -35,7 +34,9 @@ import help.screenshot.GhidraScreenShotGenerator;
public class DebuggerTargetsPluginScreenShots extends GhidraScreenShotGenerator {
@FactoryDescription(brief = "Demo Debugger", htmlDetails = "A connection for demonstration purposes")
@FactoryDescription(
brief = "Demo Debugger",
htmlDetails = "A connection for demonstration purposes")
protected static class ScreenShotDebuggerModelFactory implements DebuggerModelFactory {
private void nop() {
@@ -63,6 +64,7 @@ public class DebuggerTargetsPluginScreenShots extends GhidraScreenShotGenerator
public ScreenShotDebuggerObjectModel(String display) {
this.display = display;
addModelRoot(root);
}
@Override
@@ -79,11 +81,6 @@ public class DebuggerTargetsPluginScreenShots extends GhidraScreenShotGenerator
public AddressFactory getAddressFactory() {
throw new AssertionError();
}
@Override
public CompletableFuture<Void> close() {
return AsyncUtils.NIL;
}
}
DebuggerModelServiceInternal modelService;