mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-28 17:11:11 -09:00
GP-704: Converting models to a push-centric comm pattern.
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)?
|
||||
|
||||
@@ -34,7 +34,6 @@ public class ObjectAttributeRow {
|
||||
ref.fetch().handle(seq::next);
|
||||
}, targetObject).then(seq -> {
|
||||
to = targetObject.get();
|
||||
to.addListener(provider);
|
||||
}).finish();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user