GP-5737: Fixing GhidraScript PrintWriter

This commit is contained in:
Ryan Kurtz
2025-06-09 12:14:58 -04:00
parent 7772d98143
commit 1add5a9bce
26 changed files with 359 additions and 206 deletions

View File

@@ -4,9 +4,9 @@
* 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.
@@ -34,6 +34,7 @@ import ghidra.app.plugin.ProgramPlugin;
import ghidra.app.plugin.core.console.CodeCompletion;
import ghidra.app.plugin.core.interpreter.*;
import ghidra.app.script.GhidraState;
import ghidra.app.script.ScriptControls;
import ghidra.framework.options.OptionsChangeListener;
import ghidra.framework.options.ToolOptions;
import ghidra.framework.plugintool.PluginInfo;
@@ -232,7 +233,7 @@ public class JythonPlugin extends ProgramPlugin
interactiveScript.set(
new GhidraState(tool, tool.getProject(), getCurrentProgram(), getProgramLocation(),
getProgramSelection(), getProgramHighlight()),
interactiveTaskMonitor, new PrintWriter(getConsole().getStdOut()));
new ScriptControls(console, interactiveTaskMonitor));
interpreter.injectScriptHierarchy(interactiveScript);
interactiveTaskMonitor = new JythonInteractiveTaskMonitor(console.getStdOut());
@@ -288,7 +289,7 @@ public class JythonPlugin extends ProgramPlugin
interactiveScript.set(
new GhidraState(tool, tool.getProject(), currentProgram, currentLocation,
currentSelection, currentHighlight),
interactiveTaskMonitor, console.getOutWriter());
new ScriptControls(console, interactiveTaskMonitor));
return interpreter.getCommandCompletions(cmd, includeBuiltins, caretPos);
}
@@ -377,7 +378,7 @@ public class JythonPlugin extends ProgramPlugin
}
public JythonInteractiveTaskMonitor(OutputStream stdout) {
this(new PrintWriter(stdout));
this(new PrintWriter(stdout, true));
}
@Override

View File

@@ -4,9 +4,9 @@
* 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.
@@ -16,14 +16,15 @@
package ghidra.jython;
import java.io.File;
import java.io.PrintWriter;
import java.util.concurrent.atomic.AtomicBoolean;
import org.python.core.PyException;
import db.Transaction;
import generic.jar.ResourceFile;
import ghidra.app.plugin.core.interpreter.InterpreterConsole;
import ghidra.app.script.GhidraState;
import ghidra.app.script.ScriptControls;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.listing.Program;
import ghidra.util.task.TaskMonitor;
@@ -59,6 +60,7 @@ class JythonPluginExecutionThread extends Thread {
TaskMonitor interactiveTaskMonitor = plugin.getInteractiveTaskMonitor();
JythonScript interactiveScript = plugin.getInteractiveScript();
Program program = plugin.getCurrentProgram();
InterpreterConsole console = plugin.getConsole();
// Setup transaction for the execution.
try (Transaction tx = program != null ? program.openTransaction("Jython command") : null) {
@@ -69,7 +71,7 @@ class JythonPluginExecutionThread extends Thread {
interactiveScript.set(
new GhidraState(tool, tool.getProject(), program, plugin.getProgramLocation(),
plugin.getProgramSelection(), plugin.getProgramHighlight()),
interactiveTaskMonitor, new PrintWriter(plugin.getConsole().getStdOut()));
new ScriptControls(console, interactiveTaskMonitor));
// Execute the command
moreInputWanted.set(false);
@@ -81,14 +83,13 @@ class JythonPluginExecutionThread extends Thread {
plugin.reset();
}
else {
plugin.getConsole()
.getErrWriter()
console.getErrWriter()
.println(
"Suppressing exception: " + PyException.exceptionClassName(pye.type));
}
}
catch (StackOverflowError soe) {
plugin.getConsole().getErrWriter().println("Stack overflow!");
console.getErrWriter().println("Stack overflow!");
}
finally {
interactiveScript.end(false); // end any transactions the script may have started

View File

@@ -4,9 +4,9 @@
* 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.
@@ -62,7 +62,7 @@ public class JythonScript extends GhidraScript {
ResourceFile scriptSource = GhidraScriptUtil.findScriptByName(scriptName);
if (scriptSource != null) {
GhidraScriptProvider provider = GhidraScriptUtil.getProvider(scriptSource);
GhidraScript ghidraScript = provider.getScriptInstance(scriptSource, writer);
GhidraScript ghidraScript = provider.getScriptInstance(scriptSource, errorWriter);
if (ghidraScript == null) {
throw new IllegalArgumentException("Script does not exist: " + scriptName);
}
@@ -72,12 +72,12 @@ public class JythonScript extends GhidraScript {
}
if (ghidraScript instanceof JythonScript) {
ghidraScript.set(scriptState, monitor, writer);
ghidraScript.set(scriptState);
JythonScript jythonScript = (JythonScript) ghidraScript;
interpreter.execFile(jythonScript.getSourceFile(), jythonScript);
}
else {
ghidraScript.execute(scriptState, monitor, writer);
ghidraScript.execute(scriptState);
}
if (scriptState == state) {

View File

@@ -4,9 +4,9 @@
* 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.
@@ -25,8 +25,7 @@ import org.junit.*;
import generic.jar.ResourceFile;
import ghidra.app.plugin.core.console.ConsolePlugin;
import ghidra.app.plugin.core.osgi.BundleHost;
import ghidra.app.script.GhidraScriptUtil;
import ghidra.app.script.GhidraState;
import ghidra.app.script.*;
import ghidra.app.services.ConsoleService;
import ghidra.framework.Application;
import ghidra.framework.plugintool.PluginTool;
@@ -128,7 +127,7 @@ public class JythonScriptTest extends AbstractGhidraHeadedIntegrationTest {
JythonScriptProvider scriptProvider = new JythonScriptProvider();
PrintWriter writer = new PrintWriter(new ByteArrayOutputStream());
JythonScript script = (JythonScript) scriptProvider.getScriptInstance(scriptFile, writer);
script.set(state, TaskMonitor.DUMMY, writer);
script.set(state, new ScriptControls(writer, writer, TaskMonitor.DUMMY));
script.run();
waitForSwing();