mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-02-18 16:40:08 +00:00
GP-511: Added "Pin" toggle to interpreters.
This commit is contained in:
parent
5ea7996b7d
commit
593e9b4a22
@ -37,6 +37,7 @@ src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoint-mixed-ed.p
|
||||
src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoints-clear-all.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoints-disable-all.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoints-enable-all.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/DebuggerInterpreterPlugin/DebuggerInterpreterPlugin.html||GHIDRA||||END|
|
||||
src/main/help/help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html||GHIDRA||||END|
|
||||
src/main/help/help/topics/DebuggerListingPlugin/images/DebuggerGoToDialog.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/DebuggerListingPlugin/images/DebuggerListingPlugin.png||GHIDRA||||END|
|
||||
|
@ -78,28 +78,32 @@
|
||||
sortgroup="d"
|
||||
target="help/topics/DebuggerObjectsPlugin/DebuggerObjectsPlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerThreadsPlugin" text="Threads and Traces"
|
||||
<tocdef id="DebuggerInterpreterPlugin" text="Interpreters"
|
||||
sortgroup="e"
|
||||
target="help/topics/DebuggerInterpreterPlugin/DebuggerInterpreterPlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerThreadsPlugin" text="Threads and Traces"
|
||||
sortgroup="f"
|
||||
target="help/topics/DebuggerThreadsPlugin/DebuggerThreadsPlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerTraceManagerServicePlugin" text="Trace Management"
|
||||
sortgroup="f"
|
||||
sortgroup="g"
|
||||
target="help/topics/DebuggerTraceManagerServicePlugin/DebuggerTraceManagerServicePlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerRegistersPlugin" text="Registers"
|
||||
sortgroup="g"
|
||||
sortgroup="h"
|
||||
target="help/topics/DebuggerRegistersPlugin/DebuggerRegistersPlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerListingPlugin" text="Dynamic Listing"
|
||||
sortgroup="h"
|
||||
sortgroup="i"
|
||||
target="help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerStackPlugin" text="Stack"
|
||||
sortgroup="i"
|
||||
sortgroup="j"
|
||||
target="help/topics/DebuggerStackPlugin/DebuggerStackPlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerBreakpointsPlugin" text="Breakpoints"
|
||||
sortgroup="j"
|
||||
sortgroup="k"
|
||||
target="help/topics/DebuggerBreakpointsPlugin/DebuggerBreakpointsPlugin.html" >
|
||||
|
||||
<tocdef id="DebuggerBreakpointMarkerPlugin" text="In the Listings"
|
||||
@ -108,15 +112,15 @@
|
||||
</tocdef>
|
||||
|
||||
<tocdef id="DebuggerRegionsPlugin" text="Memory Regions"
|
||||
sortgroup="k"
|
||||
sortgroup="l"
|
||||
target="help/topics/DebuggerRegionsPlugin/DebuggerRegionsPlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerTimePlugin" text="Time"
|
||||
sortgroup="l"
|
||||
sortgroup="m"
|
||||
target="help/topics/DebuggerTimePlugin/DebuggerTimePlugin.html" />
|
||||
|
||||
<tocdef id="DebuggerModulesPlugin" text="Modules and Sections"
|
||||
sortgroup="m"
|
||||
sortgroup="n"
|
||||
target="help/topics/DebuggerModulesPlugin/DebuggerModulesPlugin.html" >
|
||||
|
||||
<tocdef id="DebuggerStaticMappingPlugin" text="Static Mappings"
|
||||
@ -125,7 +129,7 @@
|
||||
</tocdef>
|
||||
|
||||
<tocdef id="DebuggerBots" text="Bots: Workflow Automation"
|
||||
sortgroup="n"
|
||||
sortgroup="o"
|
||||
target="help/topics/DebuggerBots/DebuggerBots.html" />
|
||||
</tocdef>
|
||||
</tocref>
|
||||
|
@ -0,0 +1,46 @@
|
||||
<!DOCTYPE doctype PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN">
|
||||
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META name="generator" content=
|
||||
"HTML Tidy for Java (vers. 2009-12-01), see jtidy.sourceforge.net">
|
||||
|
||||
<TITLE>Debugger: Interpreters</TITLE>
|
||||
<META http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<LINK rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
|
||||
</HEAD>
|
||||
|
||||
<BODY lang="EN-US">
|
||||
<H1><A name="plugin"></A><A name="interpreter"></A>Debugger: Interpreters</H1>
|
||||
|
||||
<P>For debuggers which have built-in interpreters (many do), and whose connectors expose that
|
||||
interpreter in the model, the interpreters plugin can provide user access to it via a graphical
|
||||
console emulator. The plugin leverages the existing interpreter console framework in Ghidra, so
|
||||
the interface should be relatively familiar. Typically, the console is accessed via the Objects
|
||||
window's <A href=
|
||||
"help/topics/DebuggerObjectsPlugin/DebuggerObjectsPlugin.html#console">Console</A> action.
|
||||
Output is displayed in a large text field, and user input is taken via a small text field at
|
||||
the bottom. The prompt, commands, and outputs are all defined by the connector.</P>
|
||||
|
||||
<H2>Actions</H2>
|
||||
|
||||
<P>Each interpreter console has the following actions:</P>
|
||||
|
||||
<H3><A name="Clear_Interpreter"></A>Clear Interpreter</H3>
|
||||
|
||||
<P>This action is always available. It clears the console's ouput buffer.</P>
|
||||
|
||||
<H3><A name="Remove_Interpreter"></A>Remove Interpreter</H3>
|
||||
|
||||
<P>This action appears when the target's interpreter is not longer valid, i.e., the connection
|
||||
was closed. It permanently closes the console. Note this action can only appear if this console
|
||||
was pinned.</P>
|
||||
|
||||
<H3><A name="pin"></A>Pin Interpreter</H3>
|
||||
|
||||
<P>This action is always available. Normally interpreter consoles are permanently closed
|
||||
immediately upon the associated target interpreter becoming invalid, i.e., the connection was
|
||||
closed. Pinning an interpreter keeps it open, but in a disabled state, so that the buffer can
|
||||
be examined after invalidation.</P>
|
||||
</BODY>
|
||||
</HTML>
|
@ -128,12 +128,12 @@ public interface DebuggerResources {
|
||||
ImageIcon ICON_SYNC = ResourceManager.loadImage("images/sync_enabled.png");
|
||||
ImageIcon ICON_VISIBILITY = ResourceManager.loadImage("images/format-text-bold.png");
|
||||
|
||||
ImageIcon ICON_PIN = ResourceManager.loadImage("images/pin.png");
|
||||
// TODO: Find better icon?
|
||||
ImageIcon ICON_IMPORT = ResourceManager.loadImage("images/imported_bookmark.gif");
|
||||
|
||||
ImageIcon ICON_BLANK = ResourceManager.loadImage("images/blank.png");
|
||||
|
||||
ImageIcon ICON_PACKAGE = ResourceManager.loadImage("images/debugger32.png");
|
||||
|
||||
HelpLocation HELP_PACKAGE = new HelpLocation("Debugger", "package");
|
||||
|
||||
String HELP_ANCHOR_PLUGIN = "plugin";
|
||||
@ -557,12 +557,28 @@ public interface DebuggerResources {
|
||||
String HELP_ANCHOR = "disconnect_all";
|
||||
|
||||
public static ActionBuilder builder(Plugin owner, Plugin helpOwner) {
|
||||
return new ActionBuilder(owner.getName(), NAME).description(DESCRIPTION)
|
||||
return new ActionBuilder(owner.getName(), NAME)
|
||||
.description(DESCRIPTION)
|
||||
.menuIcon(ICON)
|
||||
.helpLocation(new HelpLocation(helpOwner.getName(), HELP_ANCHOR));
|
||||
}
|
||||
}
|
||||
|
||||
interface PinInterpreterAction {
|
||||
String NAME = "Pin Interpreter";
|
||||
String DESCRIPTION = "Prevent this Interpreter from closing automatically";
|
||||
Icon ICON = ICON_PIN;
|
||||
String HELP_ANCHOR = "pin";
|
||||
|
||||
public static ToggleActionBuilder builder(Plugin owner) {
|
||||
String ownerName = owner.getName();
|
||||
return new ToggleActionBuilder(ownerName, NAME)
|
||||
.description(DESCRIPTION)
|
||||
.toolBarIcon(ICON)
|
||||
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractRecordAction extends DockingAction {
|
||||
public static final String NAME = "Record";
|
||||
public static final Icon ICON = ICON_TRACE;
|
||||
|
@ -23,9 +23,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.ToggleDockingAction;
|
||||
import ghidra.app.plugin.core.console.CodeCompletion;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
||||
import ghidra.app.plugin.core.interpreter.InterpreterConnection;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.PinInterpreterAction;
|
||||
import ghidra.app.plugin.core.interpreter.InterpreterConsole;
|
||||
import ghidra.dbg.target.TargetConsole.Channel;
|
||||
import ghidra.dbg.target.TargetConsole.TargetConsoleListener;
|
||||
@ -35,7 +37,7 @@ import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public abstract class AbstractDebuggerWrappedConsoleConnection<T extends TargetObject>
|
||||
implements InterpreterConnection {
|
||||
implements DebuggerInterpreterConnection {
|
||||
|
||||
/**
|
||||
* We inherit console text output from interpreter listener, even though we may be listening to
|
||||
@ -75,8 +77,13 @@ public abstract class AbstractDebuggerWrappedConsoleConnection<T extends TargetO
|
||||
@Override
|
||||
public void invalidated(TargetObject object, String reason) {
|
||||
if (object == targetConsole) { // Redundant
|
||||
running.set(false);
|
||||
plugin.disableConsole(targetConsole, guiConsole);
|
||||
if (pinned) {
|
||||
running.set(false);
|
||||
plugin.disableConsole(targetConsole, guiConsole);
|
||||
}
|
||||
else {
|
||||
plugin.destroyConsole(targetConsole, guiConsole);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -92,6 +99,12 @@ public abstract class AbstractDebuggerWrappedConsoleConnection<T extends TargetO
|
||||
protected PrintWriter outWriter;
|
||||
protected PrintWriter errWriter;
|
||||
|
||||
protected ToggleDockingAction actionPin;
|
||||
protected boolean pinned = false;
|
||||
|
||||
// TODO: Fix InterpreterPanelService to take plugin name instead of just using title
|
||||
protected boolean firstTimeAskedTitle = true;
|
||||
|
||||
public AbstractDebuggerWrappedConsoleConnection(DebuggerInterpreterPlugin plugin,
|
||||
T targetConsole) {
|
||||
this.plugin = plugin;
|
||||
@ -103,7 +116,11 @@ public abstract class AbstractDebuggerWrappedConsoleConnection<T extends TargetO
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "Interpreter: " + targetConsole.getDisplay();
|
||||
if (firstTimeAskedTitle) {
|
||||
firstTimeAskedTitle = false;
|
||||
return plugin.getName();
|
||||
}
|
||||
return targetConsole.getDisplay();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -114,14 +131,26 @@ public abstract class AbstractDebuggerWrappedConsoleConnection<T extends TargetO
|
||||
@Override
|
||||
public List<CodeCompletion> getCompletions(String cmd) {
|
||||
// TODO: If GDB or WinDBG ever provides an API for completion....
|
||||
// TODO: Of course, that's another method on TargetInterpeter, too.
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public void setConsole(InterpreterConsole guiConsole) {
|
||||
assert this.guiConsole == null;
|
||||
this.guiConsole = guiConsole;
|
||||
setErrWriter(guiConsole.getErrWriter());
|
||||
setOutWriter(guiConsole.getOutWriter());
|
||||
setStdIn(guiConsole.getStdin());
|
||||
|
||||
createActions();
|
||||
}
|
||||
|
||||
protected void createActions() {
|
||||
actionPin = PinInterpreterAction.builder(plugin)
|
||||
.onAction(this::activatedPin)
|
||||
.selected(pinned)
|
||||
.build();
|
||||
guiConsole.addAction(actionPin);
|
||||
}
|
||||
|
||||
public void setOutWriter(PrintWriter outWriter) {
|
||||
@ -142,6 +171,10 @@ public abstract class AbstractDebuggerWrappedConsoleConnection<T extends TargetO
|
||||
thread.start();
|
||||
}
|
||||
|
||||
private void activatedPin(ActionContext ignore) {
|
||||
pinned = actionPin.isSelected();
|
||||
}
|
||||
|
||||
protected void run() {
|
||||
try {
|
||||
while (running.get()) {
|
||||
@ -164,4 +197,25 @@ public abstract class AbstractDebuggerWrappedConsoleConnection<T extends TargetO
|
||||
Msg.debug(this, "Lost console?");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InterpreterConsole getInterpreterConsole() {
|
||||
return guiConsole;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetObject getTargetConsole() {
|
||||
return targetConsole;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPinned() {
|
||||
return pinned;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPinned(boolean pinned) {
|
||||
this.pinned = pinned;
|
||||
actionPin.setSelected(pinned);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
/* ###
|
||||
* 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.interpreters;
|
||||
|
||||
import ghidra.app.plugin.core.interpreter.InterpreterConnection;
|
||||
import ghidra.app.plugin.core.interpreter.InterpreterConsole;
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
|
||||
public interface DebuggerInterpreterConnection extends InterpreterConnection {
|
||||
void setPinned(boolean pinned);
|
||||
|
||||
boolean isPinned();
|
||||
|
||||
TargetObject getTargetConsole();
|
||||
|
||||
InterpreterConsole getInterpreterConsole();
|
||||
}
|
@ -51,66 +51,77 @@ public class DebuggerInterpreterPlugin extends AbstractDebuggerPlugin
|
||||
@AutoServiceConsumed
|
||||
protected InterpreterPanelService consoleService;
|
||||
|
||||
protected final Map<TargetObject, InterpreterConsole> consoles = new HashMap<>();
|
||||
protected final Map<TargetObject, DebuggerInterpreterConnection> connections = new HashMap<>();
|
||||
|
||||
public DebuggerInterpreterPlugin(PluginTool tool) {
|
||||
super(tool);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showConsole(TargetConsole<?> targetConsole) {
|
||||
InterpreterConsole console;
|
||||
synchronized (consoles) {
|
||||
console = consoles.computeIfAbsent(targetConsole, c -> createConsole(targetConsole));
|
||||
public DebuggerInterpreterConnection showConsole(TargetConsole<?> targetConsole) {
|
||||
DebuggerInterpreterConnection conn;
|
||||
synchronized (connections) {
|
||||
conn = connections.computeIfAbsent(targetConsole, c -> createConnection(targetConsole));
|
||||
}
|
||||
console.show();
|
||||
conn.getInterpreterConsole().show();
|
||||
return conn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showConsole(TargetInterpreter<?> targetInterpreter) {
|
||||
InterpreterConsole console;
|
||||
synchronized (consoles) {
|
||||
console =
|
||||
consoles.computeIfAbsent(targetInterpreter, c -> createConsole(targetInterpreter));
|
||||
public DebuggerInterpreterConnection showConsole(TargetInterpreter<?> targetInterpreter) {
|
||||
DebuggerInterpreterConnection conn;
|
||||
synchronized (connections) {
|
||||
conn = connections.computeIfAbsent(targetInterpreter,
|
||||
c -> createConnection(targetInterpreter));
|
||||
}
|
||||
console.show();
|
||||
conn.getInterpreterConsole().show();
|
||||
return conn;
|
||||
}
|
||||
|
||||
protected void disableConsole(TargetObject targetConsole, InterpreterConsole guiConsole) {
|
||||
InterpreterConsole old = consoles.get(targetConsole);
|
||||
assert old == guiConsole;
|
||||
DebuggerInterpreterConnection old;
|
||||
synchronized (connections) {
|
||||
old = connections.remove(targetConsole);
|
||||
}
|
||||
assert old.getInterpreterConsole() == guiConsole;
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
if (guiConsole.isInputPermitted()) {
|
||||
guiConsole.setInputPermitted(false);
|
||||
guiConsole.setTransient();
|
||||
guiConsole.setPrompt(">>INVALID<<");
|
||||
/**
|
||||
* TODO: Should invisible ones just be removed?
|
||||
*
|
||||
* TODO: Would like setTransient to work like other providers, but
|
||||
* InterpreterComponentProvider overrides it.... For now, I leave invisible disabled
|
||||
* ones in the tool. User must show and click custom "remove interpreter" action.
|
||||
*/
|
||||
/*if (!console.isVisible()) {
|
||||
console.dispose();
|
||||
}*/
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected InterpreterConsole createConsole(
|
||||
AbstractDebuggerWrappedConsoleConnection<?> connection) {
|
||||
protected void createConsole(AbstractDebuggerWrappedConsoleConnection<?> connection) {
|
||||
InterpreterConsole console = consoleService.createInterpreterPanel(connection, true);
|
||||
connection.setConsole(console);
|
||||
connection.runInBackground();
|
||||
return console;
|
||||
}
|
||||
|
||||
protected InterpreterConsole createConsole(TargetConsole<?> targetConsole) {
|
||||
return createConsole(new DebuggerWrappedConsoleConnection(this, targetConsole));
|
||||
protected DebuggerInterpreterConnection createConnection(TargetConsole<?> targetConsole) {
|
||||
DebuggerWrappedConsoleConnection conn =
|
||||
new DebuggerWrappedConsoleConnection(this, targetConsole);
|
||||
createConsole(conn);
|
||||
return conn;
|
||||
}
|
||||
|
||||
protected InterpreterConsole createConsole(TargetInterpreter<?> targetInterpreter) {
|
||||
return createConsole(new DebuggerWrappedInterpreterConnection(this, targetInterpreter));
|
||||
protected DebuggerInterpreterConnection createConnection(
|
||||
TargetInterpreter<?> targetInterpreter) {
|
||||
DebuggerWrappedInterpreterConnection conn =
|
||||
new DebuggerWrappedInterpreterConnection(this, targetInterpreter);
|
||||
createConsole(conn);
|
||||
return conn;
|
||||
}
|
||||
|
||||
public void destroyConsole(TargetObject targetConsole, InterpreterConsole guiConsole) {
|
||||
DebuggerInterpreterConnection old;
|
||||
synchronized (connections) {
|
||||
old = connections.remove(targetConsole);
|
||||
}
|
||||
assert old.getInterpreterConsole() == guiConsole;
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
guiConsole.dispose();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -301,32 +301,37 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
|
||||
|
||||
@Override
|
||||
public void closeAllTraces() {
|
||||
for (Trace trace : getOpenTraces()) {
|
||||
closeTrace(trace);
|
||||
}
|
||||
Swing.runIfSwingOrRunLater(() -> {
|
||||
for (Trace trace : getOpenTraces()) {
|
||||
closeTrace(trace);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeOtherTraces(Trace keep) {
|
||||
for (Trace trace : getOpenTraces()) {
|
||||
if (trace != keep) {
|
||||
closeTrace(trace);
|
||||
Swing.runIfSwingOrRunLater(() -> {
|
||||
for (Trace trace : getOpenTraces()) {
|
||||
if (trace != keep) {
|
||||
closeTrace(trace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeDeadTraces() {
|
||||
if (modelService == null) {
|
||||
return;
|
||||
}
|
||||
for (Trace trace : getOpenTraces()) {
|
||||
TraceRecorder recorder = modelService.getRecorder(trace);
|
||||
if (recorder == null) {
|
||||
closeTrace(trace);
|
||||
Swing.runIfSwingOrRunLater(() -> {
|
||||
if (modelService == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (Trace trace : getOpenTraces()) {
|
||||
TraceRecorder recorder = modelService.getRecorder(trace);
|
||||
if (recorder == null) {
|
||||
closeTrace(trace);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@AutoServiceConsumed
|
||||
@ -837,10 +842,16 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
|
||||
|
||||
@Override
|
||||
public void closeTrace(Trace trace) {
|
||||
if (trace.getConsumerList().contains(this)) {
|
||||
firePluginEvent(new TraceClosedPluginEvent(getName(), trace));
|
||||
doTraceClosed(trace);
|
||||
}
|
||||
/**
|
||||
* A provider may be reading the trace, likely via the Swing thread, so schedule this on the
|
||||
* same thread to avoid a ClosedException.
|
||||
*/
|
||||
Swing.runIfSwingOrRunLater(() -> {
|
||||
if (trace.getConsumerList().contains(this)) {
|
||||
firePluginEvent(new TraceClosedPluginEvent(getName(), trace));
|
||||
doTraceClosed(trace);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package ghidra.app.services;
|
||||
|
||||
import ghidra.app.plugin.core.debug.gui.interpreters.DebuggerInterpreterConnection;
|
||||
import ghidra.app.plugin.core.debug.gui.interpreters.DebuggerInterpreterPlugin;
|
||||
import ghidra.dbg.target.TargetConsole;
|
||||
import ghidra.dbg.target.TargetInterpreter;
|
||||
@ -25,7 +26,7 @@ import ghidra.framework.plugintool.ServiceInfo;
|
||||
description = "Service for managing debugger interpreter panels" //
|
||||
)
|
||||
public interface DebuggerInterpreterService {
|
||||
void showConsole(TargetConsole<?> console);
|
||||
DebuggerInterpreterConnection showConsole(TargetConsole<?> console);
|
||||
|
||||
void showConsole(TargetInterpreter<?> interpreter);
|
||||
DebuggerInterpreterConnection showConsole(TargetInterpreter<?> interpreter);
|
||||
}
|
||||
|
@ -22,7 +22,8 @@ import java.awt.event.KeyEvent;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.*;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
|
||||
import ghidra.app.plugin.core.interpreter.InterpreterComponentProvider;
|
||||
@ -112,7 +113,7 @@ public class DebuggerInterpreterPluginTest extends AbstractGhidraHeadedDebuggerG
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidateInterpreterDisablesConsole() throws Exception {
|
||||
public void testInvalidateInterpreterDestroysConsole() throws Exception {
|
||||
createTestModel();
|
||||
interpreterPlugin.showConsole(mb.testModel.session.interpreter);
|
||||
InterpreterComponentProvider interpreter =
|
||||
@ -123,44 +124,24 @@ public class DebuggerInterpreterPluginTest extends AbstractGhidraHeadedDebuggerG
|
||||
), Map.of(), "Invalidate interpreter");
|
||||
waitForSwing();
|
||||
|
||||
assertFalse(interpreter.isVisible());
|
||||
assertFalse(interpreter.isInTool());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidatePinnedInterpreterDisablesConsole() throws Exception {
|
||||
createTestModel();
|
||||
DebuggerInterpreterConnection conn =
|
||||
interpreterPlugin.showConsole(mb.testModel.session.interpreter);
|
||||
InterpreterComponentProvider interpreter =
|
||||
waitForComponentProvider(InterpreterComponentProvider.class);
|
||||
conn.setPinned(true);
|
||||
|
||||
mb.testModel.session.changeAttributes(List.of(
|
||||
"Interpreter" //
|
||||
), Map.of(), "Invalidate interpreter");
|
||||
waitForSwing();
|
||||
|
||||
assertFalse(interpreter.isInputPermitted());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Haven't decided on proper behavior")
|
||||
public void testInvalidateClosedDestroysConsole() throws Exception {
|
||||
createTestModel();
|
||||
interpreterPlugin.showConsole(mb.testModel.session.interpreter);
|
||||
InterpreterComponentProvider interpreter =
|
||||
waitForComponentProvider(InterpreterComponentProvider.class);
|
||||
|
||||
interpreter.setVisible(false);
|
||||
waitForSwing();
|
||||
|
||||
mb.testModel.session.changeAttributes(List.of(
|
||||
"Interpreter" //
|
||||
), Map.of(), "Invalidate interpreter");
|
||||
waitForSwing();
|
||||
|
||||
assertFalse(interpreter.isInTool());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Haven't decided on proper behavior")
|
||||
public void testCloseInvalidatedDestroysConsole() throws Exception {
|
||||
createTestModel();
|
||||
interpreterPlugin.showConsole(mb.testModel.session.interpreter);
|
||||
InterpreterComponentProvider interpreter =
|
||||
waitForComponentProvider(InterpreterComponentProvider.class);
|
||||
|
||||
mb.testModel.session.changeAttributes(List.of(
|
||||
"Interpreter" //
|
||||
), Map.of(), "Invalidate interpreter");
|
||||
waitForSwing();
|
||||
|
||||
interpreter.setVisible(false);
|
||||
waitForSwing();
|
||||
|
||||
assertFalse(interpreter.isInTool());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user