mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +02:00
Merge remote-tracking branch 'origin/GP-5737_ryanmkurtz_script-output--SQUASHED'
This commit is contained in:
commit
c224c5d44e
26 changed files with 359 additions and 206 deletions
|
@ -15,8 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.script;
|
package ghidra.app.plugin.core.script;
|
||||||
|
|
||||||
import ghidra.app.script.GhidraScript;
|
import ghidra.app.script.*;
|
||||||
import ghidra.app.script.GhidraState;
|
|
||||||
import ghidra.app.services.ConsoleService;
|
import ghidra.app.services.ConsoleService;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
|
@ -44,7 +43,7 @@ class RunScriptTask extends Task {
|
||||||
Thread.currentThread().setName(scriptName);
|
Thread.currentThread().setName(scriptName);
|
||||||
|
|
||||||
console.addMessage(scriptName, "Running...");
|
console.addMessage(scriptName, "Running...");
|
||||||
script.execute(currentState, monitor, console.getStdOut());
|
script.execute(currentState, new ScriptControls(console, monitor));
|
||||||
console.addMessage(scriptName, "Finished!");
|
console.addMessage(scriptName, "Finished!");
|
||||||
}
|
}
|
||||||
catch (CancelledException e) {
|
catch (CancelledException e) {
|
||||||
|
|
|
@ -37,7 +37,8 @@ import ghidra.app.plugin.core.analysis.AnalysisWorker;
|
||||||
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
|
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
|
||||||
import ghidra.app.plugin.core.colorizer.ColorizingService;
|
import ghidra.app.plugin.core.colorizer.ColorizingService;
|
||||||
import ghidra.app.plugin.core.table.TableComponentProvider;
|
import ghidra.app.plugin.core.table.TableComponentProvider;
|
||||||
import ghidra.app.services.*;
|
import ghidra.app.services.GoToService;
|
||||||
|
import ghidra.app.services.ProgramManager;
|
||||||
import ghidra.app.tablechooser.TableChooserDialog;
|
import ghidra.app.tablechooser.TableChooserDialog;
|
||||||
import ghidra.app.tablechooser.TableChooserExecutor;
|
import ghidra.app.tablechooser.TableChooserExecutor;
|
||||||
import ghidra.app.util.demangler.DemangledObject;
|
import ghidra.app.util.demangler.DemangledObject;
|
||||||
|
@ -142,6 +143,8 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
protected ResourceFile sourceFile;
|
protected ResourceFile sourceFile;
|
||||||
protected GhidraState state;
|
protected GhidraState state;
|
||||||
protected PrintWriter writer;
|
protected PrintWriter writer;
|
||||||
|
protected PrintWriter errorWriter;
|
||||||
|
protected boolean decorateOutput;
|
||||||
protected Address currentAddress;
|
protected Address currentAddress;
|
||||||
protected ProgramLocation currentLocation;
|
protected ProgramLocation currentLocation;
|
||||||
protected ProgramSelection currentSelection;
|
protected ProgramSelection currentSelection;
|
||||||
|
@ -192,18 +195,47 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the context for this script.
|
* Set the context for this script.
|
||||||
|
* <p>
|
||||||
|
* This method will use the given {@link PrintWriter} for both {@code stdout} and
|
||||||
|
* {@code stderr}.
|
||||||
*
|
*
|
||||||
* @param state state object
|
* @param state state object
|
||||||
* @param monitor the monitor to use during run
|
* @param monitor the monitor to use during run
|
||||||
* @param writer the target of script "print" statements
|
* @param writer the target of script "print" statements (may be null)
|
||||||
|
* @deprecated Use {@link #set(GhidraState)} or {@link #set(GhidraState, ScriptControls)}
|
||||||
|
* instead
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(since = "11.5")
|
||||||
public final void set(GhidraState state, TaskMonitor monitor, PrintWriter writer) {
|
public final void set(GhidraState state, TaskMonitor monitor, PrintWriter writer) {
|
||||||
|
set(state, new ScriptControls(writer, writer, monitor));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the context for this script.
|
||||||
|
*
|
||||||
|
* @param state the new state
|
||||||
|
*/
|
||||||
|
public final void set(GhidraState state) {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
this.monitor = monitor;
|
|
||||||
this.writer = writer;
|
|
||||||
loadVariablesFromState();
|
loadVariablesFromState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the state and controls for this script.
|
||||||
|
*
|
||||||
|
* @param state the new state
|
||||||
|
* @param controls new the controls
|
||||||
|
*/
|
||||||
|
public final void set(GhidraState state, ScriptControls controls) {
|
||||||
|
this.state = state;
|
||||||
|
loadVariablesFromState();
|
||||||
|
|
||||||
|
this.writer = controls.getWriter();
|
||||||
|
this.errorWriter = controls.getErrorWriter();
|
||||||
|
this.decorateOutput = controls.shouldDecorateOutput();
|
||||||
|
this.monitor = controls.getMonitor();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether the user's previously selected values should be used when showing the various
|
* Sets whether the user's previously selected values should be used when showing the various
|
||||||
* {@code ask} methods. This is true by default, meaning that previous choices will be shown
|
* {@code ask} methods. This is true by default, meaning that previous choices will be shown
|
||||||
|
@ -225,17 +257,51 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute/run script and {@link #doCleanup} afterwards.
|
* Execute/run script and {@link #doCleanup} afterwards.
|
||||||
|
* <p>
|
||||||
|
* This method will use the given {@link PrintWriter} for both {@code stdout} and
|
||||||
|
* {@code stderr}.
|
||||||
*
|
*
|
||||||
* @param runState state object
|
* @param runState state object
|
||||||
* @param runMonitor the monitor to use during run
|
* @param runMonitor the monitor to use during run
|
||||||
* @param runWriter the target of script "print" statements
|
* @param runWriter the target of script "print" statements (may be null)
|
||||||
|
* @throws Exception if the script excepts
|
||||||
|
* @deprecated Use {@link #execute(GhidraState, ScriptControls)} instead to also set a
|
||||||
|
* {@link PrintWriter} for {@code stderr}
|
||||||
|
*/
|
||||||
|
@Deprecated(since = "11.5")
|
||||||
|
public final void execute(GhidraState runState, TaskMonitor runMonitor, PrintWriter runWriter)
|
||||||
|
throws Exception {
|
||||||
|
execute(runState, new ScriptControls(runWriter, runWriter, runMonitor));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute/run script with the given {@link GhidraState state} and current
|
||||||
|
* {@link ScriptControls controls} and {@link #doCleanup} afterwards.
|
||||||
|
* <p>
|
||||||
|
* NOTE: This method is not intended to be called by script writers.
|
||||||
|
*
|
||||||
|
* @param runState state object
|
||||||
* @throws Exception if the script excepts
|
* @throws Exception if the script excepts
|
||||||
*/
|
*/
|
||||||
public final void execute(GhidraState runState, TaskMonitor runMonitor, PrintWriter runWriter)
|
public final void execute(GhidraState runState) throws Exception {
|
||||||
|
execute(runState, new ScriptControls(writer, errorWriter, decorateOutput, monitor));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute/run script with the given {@link GhidraState state} and
|
||||||
|
* {@link ScriptControls controls} and {@link #doCleanup} afterwards.
|
||||||
|
* <p>
|
||||||
|
* NOTE: This method is not intended to be called by script writers.
|
||||||
|
*
|
||||||
|
* @param runState state object
|
||||||
|
* @param runControls controls object
|
||||||
|
* @throws Exception if the script excepts
|
||||||
|
*/
|
||||||
|
public final void execute(GhidraState runState, ScriptControls runControls)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
try {
|
try {
|
||||||
doExecute(runState, runMonitor, runWriter);
|
doExecute(runState, runControls);
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -243,11 +309,13 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doExecute(GhidraState runState, TaskMonitor runMonitor, PrintWriter runWriter)
|
private void doExecute(GhidraState runState, ScriptControls runControls)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
this.state = runState;
|
this.state = runState;
|
||||||
this.monitor = runMonitor;
|
this.writer = runControls.getWriter();
|
||||||
this.writer = runWriter;
|
this.errorWriter = runControls.getErrorWriter();
|
||||||
|
this.decorateOutput = runControls.shouldDecorateOutput();
|
||||||
|
this.monitor = runControls.getMonitor();
|
||||||
loadVariablesFromState();
|
loadVariablesFromState();
|
||||||
|
|
||||||
loadPropertiesFile();
|
loadPropertiesFile();
|
||||||
|
@ -260,7 +328,8 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
executeNormal();
|
executeNormal();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
executeAsAnalysisWorker(scriptAnalysisMode == AnalysisMode.SUSPENDED, runMonitor);
|
executeAsAnalysisWorker(scriptAnalysisMode == AnalysisMode.SUSPENDED,
|
||||||
|
runControls.getMonitor());
|
||||||
}
|
}
|
||||||
updateStateFromVariables();
|
updateStateFromVariables();
|
||||||
}
|
}
|
||||||
|
@ -844,7 +913,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
"': unable to run this script type.");
|
"': unable to run this script type.");
|
||||||
}
|
}
|
||||||
|
|
||||||
GhidraScript script = provider.getScriptInstance(scriptSource, writer);
|
GhidraScript script = provider.getScriptInstance(scriptSource, errorWriter);
|
||||||
script.setScriptArgs(scriptArguments);
|
script.setScriptArgs(scriptArguments);
|
||||||
|
|
||||||
if (potentialPropertiesFileLocs.size() > 0) {
|
if (potentialPropertiesFileLocs.size() > 0) {
|
||||||
|
@ -855,7 +924,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
updateStateFromVariables();
|
updateStateFromVariables();
|
||||||
}
|
}
|
||||||
|
|
||||||
script.execute(scriptState, monitor, writer);
|
script.execute(scriptState);
|
||||||
|
|
||||||
if (scriptState == state) {
|
if (scriptState == state) {
|
||||||
loadVariablesFromState();
|
loadVariablesFromState();
|
||||||
|
@ -949,74 +1018,44 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints a newline.
|
* Prints a newline to this script's {@code stdout} {@link PrintWriter}, which is set by
|
||||||
*
|
* {@link #set(GhidraState, ScriptControls)}.
|
||||||
* @see #printf(String, Object...)
|
* <p>
|
||||||
|
* Additionally, the newline is written to Ghidra's log.
|
||||||
*/
|
*/
|
||||||
public void println() {
|
public void println() {
|
||||||
println("");
|
println("");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints the message to the console followed by a line feed.
|
* Prints the {@link #decorateOutput optionally} {@link #decorate(String) decorated} message
|
||||||
|
* followed by a line feed to this script's {@code stdout} {@link PrintWriter}, which is set by
|
||||||
|
* {@link #set(GhidraState, ScriptControls)}.
|
||||||
|
* <p>
|
||||||
|
* Additionally, the always {@link #decorate(String) decorated} message is written to Ghidra's
|
||||||
|
* log.
|
||||||
*
|
*
|
||||||
* @param message the message to print
|
* @param message the message to print
|
||||||
* @see #printf(String, Object...)
|
|
||||||
*/
|
*/
|
||||||
public void println(String message) {
|
public void println(String message) {
|
||||||
String decoratedMessage = getScriptName() + "> " + message;
|
String decoratedMessage = decorate(message);
|
||||||
|
|
||||||
// note: use a Message object to facilitate script message log filtering
|
|
||||||
Msg.info(GhidraScript.class, new ScriptMessage(decoratedMessage));
|
Msg.info(GhidraScript.class, new ScriptMessage(decoratedMessage));
|
||||||
|
|
||||||
if (isRunningHeadless()) {
|
if (writer != null) {
|
||||||
return;
|
writer.println(decorateOutput ? decoratedMessage : message);
|
||||||
}
|
|
||||||
|
|
||||||
PluginTool tool = state.getTool();
|
|
||||||
if (tool == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConsoleService console = tool.getService(ConsoleService.class);
|
|
||||||
if (console == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
console.addMessage(getScriptName(), message);
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
Msg.error(this, "Script Message: " + message, e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A convenience method to print a formatted String using Java's <code>printf</code>
|
* Prints the undecorated {@link java.util.Formatter formatted message} to this script's
|
||||||
* feature, which is similar to that of the C programming language.
|
* {@code stdout} {@link PrintWriter}, which is set by
|
||||||
* For a full description on Java's
|
* {@link #set(GhidraState, ScriptControls)}.
|
||||||
* <code>printf</code> usage, see {@link java.util.Formatter}.
|
|
||||||
* <p>
|
* <p>
|
||||||
* For examples, see the included <code>FormatExampleScript</code>.
|
* Additionally, the undecorated formatted message is written to Ghidra's log.
|
||||||
* <p>
|
|
||||||
* <b><u>Note:</u> This method will not:</b>
|
|
||||||
* <ul>
|
|
||||||
* <li><b>print out the name of the script, as does {@link #println(String)}</b></li>
|
|
||||||
* <li><b>print a newline</b></li>
|
|
||||||
* </ul>
|
|
||||||
* If you would like the name of the script to precede you message, then you must add that
|
|
||||||
* yourself. The {@link #println(String)} does this via the following code:
|
|
||||||
* <pre>
|
|
||||||
* String messageWithSource = getScriptName() + "> " + message;
|
|
||||||
* </pre>
|
|
||||||
*
|
*
|
||||||
* @param message the message to format
|
* @param message the message to format
|
||||||
* @param args formatter arguments (see above)
|
* @param args C-like {@code printf} formatter arguments
|
||||||
*
|
|
||||||
* @see String#format(String, Object...)
|
|
||||||
* @see java.util.Formatter
|
|
||||||
* @see #print(String)
|
|
||||||
* @see #println(String)
|
|
||||||
*/
|
*/
|
||||||
public void printf(String message, Object... args) {
|
public void printf(String message, Object... args) {
|
||||||
String formattedString = String.format(message, args);
|
String formattedString = String.format(message, args);
|
||||||
|
@ -1024,20 +1063,12 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints the message to the console - no line feed
|
* Prints the undecorated message with no newline to this script's {@code stdout}
|
||||||
|
* {@link PrintWriter}, which is set by {@link #set(GhidraState, ScriptControls)}.
|
||||||
* <p>
|
* <p>
|
||||||
* <b><u>Note:</u> This method will not print out the name of the script,
|
* Additionally, the undecorated message is written to Ghidra's log.
|
||||||
* as does {@link #println(String)}
|
|
||||||
* </b>
|
|
||||||
* <p>
|
|
||||||
* If you would like the name of the script to precede you message, then you must add that
|
|
||||||
* yourself. The {@link #println(String)} does this via the following code:
|
|
||||||
* <pre>
|
|
||||||
* String messageWithSource = getScriptName() + "> " + message;
|
|
||||||
* </pre>
|
|
||||||
*
|
*
|
||||||
* @param message the message to print
|
* @param message the message to print
|
||||||
* @see #printf(String, Object...)
|
|
||||||
*/
|
*/
|
||||||
public void print(String message) {
|
public void print(String message) {
|
||||||
// clients using print may add their own newline, which interferes with our logging,
|
// clients using print may add their own newline, which interferes with our logging,
|
||||||
|
@ -1051,57 +1082,41 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
}
|
}
|
||||||
Msg.info(GhidraScript.class, new ScriptMessage(strippedMessage));
|
Msg.info(GhidraScript.class, new ScriptMessage(strippedMessage));
|
||||||
|
|
||||||
if (isRunningHeadless()) {
|
if (writer != null) {
|
||||||
return;
|
writer.print(message);
|
||||||
}
|
|
||||||
|
|
||||||
PluginTool tool = state.getTool();
|
|
||||||
if (tool == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConsoleService console = tool.getService(ConsoleService.class);
|
|
||||||
if (console == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
console.print(message);
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
Msg.error(this, "Script Message: " + message, e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints the error message to the console followed by a line feed.
|
* Prints the {@link #decorateOutput optionally} {@link #decorate(String) decorated} message
|
||||||
|
* followed by a line feed to this script's {@code stderr} {@link PrintWriter}, which is set by
|
||||||
|
* {@link #set(GhidraState, ScriptControls)}.
|
||||||
|
* <p>
|
||||||
|
* Additionally, the always {@link #decorate(String) decorated} message is written to Ghidra's
|
||||||
|
* log as an error.
|
||||||
*
|
*
|
||||||
* @param message the error message to print
|
* @param message the message to print
|
||||||
*/
|
*/
|
||||||
public void printerr(String message) {
|
public void printerr(String message) {
|
||||||
String msgMessage = getScriptName() + "> " + message;
|
String decoratedMessage = decorate(message);
|
||||||
Msg.error(GhidraScript.class, new ScriptMessage(msgMessage));
|
|
||||||
|
|
||||||
if (isRunningHeadless()) {
|
Msg.error(GhidraScript.class, new ScriptMessage(decoratedMessage));
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PluginTool tool = state.getTool();
|
if (errorWriter != null) {
|
||||||
if (tool == null) {
|
errorWriter.println(decorateOutput ? decoratedMessage : message);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ConsoleService console = tool.getService(ConsoleService.class);
|
/**
|
||||||
if (console == null) {
|
* Decorates the given message, which is used by the {@link GhidraScript} "print" methods during
|
||||||
return;
|
* logging and {@link #decorateOutput optionally} when outputting to the
|
||||||
}
|
* {@link PrintWriter}s.
|
||||||
|
*
|
||||||
try {
|
* @param message The message to decorate
|
||||||
console.addErrorMessage(getScriptName(), message);
|
* @return The decorated message
|
||||||
}
|
*/
|
||||||
catch (Exception e) {
|
protected String decorate(String message) {
|
||||||
Msg.error(this, "Script Message: " + message, e);
|
return getScriptName() + "> " + message;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3685,7 +3700,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
pm.openProgram(program);
|
pm.openProgram(program);
|
||||||
end(true);
|
end(true);
|
||||||
GhidraState newState = new GhidraState(tool, tool.getProject(), program, null, null, null);
|
GhidraState newState = new GhidraState(tool, tool.getProject(), program, null, null, null);
|
||||||
set(newState, monitor, writer);
|
set(newState);
|
||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,12 +87,12 @@ public abstract class GhidraScriptProvider
|
||||||
* Returns a GhidraScript instance for the specified source file.
|
* Returns a GhidraScript instance for the specified source file.
|
||||||
*
|
*
|
||||||
* @param sourceFile the source file
|
* @param sourceFile the source file
|
||||||
* @param writer the print writer to write warning/error messages. If the error prevents
|
* @param errorWriter the print writer to write warning/error messages. If the error prevents
|
||||||
* success, throw an exception instead. The caller will print the error.
|
* success, throw an exception instead. The caller will print the error.
|
||||||
* @return a GhidraScript instance for the specified source file
|
* @return a GhidraScript instance for the specified source file
|
||||||
* @throws GhidraScriptLoadException when the script instance cannot be created
|
* @throws GhidraScriptLoadException when the script instance cannot be created
|
||||||
*/
|
*/
|
||||||
public abstract GhidraScript getScriptInstance(ResourceFile sourceFile, PrintWriter writer)
|
public abstract GhidraScript getScriptInstance(ResourceFile sourceFile, PrintWriter errorWriter)
|
||||||
throws GhidraScriptLoadException;
|
throws GhidraScriptLoadException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
/* ###
|
||||||
|
* 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.script;
|
||||||
|
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
|
import ghidra.app.plugin.core.interpreter.InterpreterConsole;
|
||||||
|
import ghidra.app.services.ConsoleService;
|
||||||
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to encapsulate {@link GhidraScript} control mechanisms such as stdout/stderr writers and
|
||||||
|
* other feedback to the user
|
||||||
|
*/
|
||||||
|
public class ScriptControls {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link ScriptControls} that does nothing
|
||||||
|
*/
|
||||||
|
public static final ScriptControls NONE =
|
||||||
|
new ScriptControls(null, null, false, TaskMonitor.DUMMY);
|
||||||
|
|
||||||
|
private PrintWriter writer;
|
||||||
|
private PrintWriter errorWriter;
|
||||||
|
private boolean decorateOutput;
|
||||||
|
private TaskMonitor monitor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link ScriptControls}
|
||||||
|
*
|
||||||
|
* @param writer The target of script "print" statements (may be null)
|
||||||
|
* @param errorWriter The target of script "printerr" statements (may be null)
|
||||||
|
* @param decorateOutput True to decorate the writer output with a script name prefix;
|
||||||
|
* otherwise, false (see {@link GhidraScript#decorate(String)}
|
||||||
|
* @param monitor A cancellable monitor
|
||||||
|
*/
|
||||||
|
public ScriptControls(PrintWriter writer, PrintWriter errorWriter, boolean decorateOutput,
|
||||||
|
TaskMonitor monitor) {
|
||||||
|
this.writer = writer;
|
||||||
|
this.errorWriter = errorWriter;
|
||||||
|
this.decorateOutput = decorateOutput;
|
||||||
|
this.monitor = monitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link ScriptControls} with no decorated output
|
||||||
|
*
|
||||||
|
* @param writer The target of script "print" statements (may be null)
|
||||||
|
* @param errorWriter The target of script "printerr" statements (may be null)
|
||||||
|
* otherwise, false (see {@link GhidraScript#decorate(String)}
|
||||||
|
* @param monitor A cancellable monitor
|
||||||
|
*/
|
||||||
|
public ScriptControls(PrintWriter writer, PrintWriter errorWriter, TaskMonitor monitor) {
|
||||||
|
this(writer, errorWriter, false, monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link ScriptControls} with no decorated output
|
||||||
|
*
|
||||||
|
* @param stream The target of script "print" statements (may be null)
|
||||||
|
* @param errorStream The target of script "printerr" statements (may be null)
|
||||||
|
* otherwise, false (see {@link GhidraScript#decorate(String)}
|
||||||
|
* @param monitor A cancellable monitor
|
||||||
|
*/
|
||||||
|
public ScriptControls(OutputStream stream, OutputStream errorStream, TaskMonitor monitor) {
|
||||||
|
this(new PrintWriter(stream, true), new PrintWriter(errorStream, true), false, monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link ScriptControls} with no decorated output
|
||||||
|
*
|
||||||
|
* @param console The target of script "print" and "printerr" statements
|
||||||
|
* @param monitor A cancellable monitor
|
||||||
|
*/
|
||||||
|
public ScriptControls(ConsoleService console, TaskMonitor monitor) {
|
||||||
|
this(console.getStdOut(), console.getStdErr(), monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link ScriptControls} with no decorated output
|
||||||
|
*
|
||||||
|
* @param console The target of script "print" and "printerr" statements
|
||||||
|
* @param monitor A cancellable monitor
|
||||||
|
*/
|
||||||
|
public ScriptControls(InterpreterConsole console, TaskMonitor monitor) {
|
||||||
|
this(console.getStdOut(), console.getStdErr(), monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the target of script "print" statements (may be null)}
|
||||||
|
*/
|
||||||
|
public PrintWriter getWriter() {
|
||||||
|
return writer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the target of script "printerr" statements (may be null)}
|
||||||
|
*/
|
||||||
|
public PrintWriter getErrorWriter() {
|
||||||
|
return errorWriter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return True to decorate the writer output with a script name prefix; otherwise, false}
|
||||||
|
*
|
||||||
|
* @see GhidraScript#decorate(String)
|
||||||
|
*/
|
||||||
|
public boolean shouldDecorateOutput() {
|
||||||
|
return decorateOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return A cancellable monitor}
|
||||||
|
*/
|
||||||
|
public TaskMonitor getMonitor() {
|
||||||
|
return monitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -77,10 +77,9 @@ public class GhidraScriptRunner implements GhidraLaunchable {
|
||||||
srcFile != null ? srcFile.getAbsolutePath() : (script.getClass().getName() + ".class");
|
srcFile != null ? srcFile.getAbsolutePath() : (script.getClass().getName() + ".class");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
PrintWriter writer = new PrintWriter(System.out);
|
|
||||||
Msg.info(this, "SCRIPT: " + scriptName);
|
Msg.info(this, "SCRIPT: " + scriptName);
|
||||||
script.execute(scriptState, TaskMonitor.DUMMY, writer);
|
ScriptControls controls = new ScriptControls(System.out, System.err, TaskMonitor.DUMMY);
|
||||||
writer.flush();
|
script.execute(scriptState, controls);
|
||||||
}
|
}
|
||||||
catch (Exception exc) {
|
catch (Exception exc) {
|
||||||
Program prog = scriptState.getCurrentProgram();
|
Program prog = scriptState.getCurrentProgram();
|
||||||
|
@ -107,8 +106,8 @@ public class GhidraScriptRunner implements GhidraLaunchable {
|
||||||
"ensure you have installed the necessary plugin.");
|
"ensure you have installed the necessary plugin.");
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintWriter writer = new PrintWriter(System.out);
|
PrintWriter errWriter = new PrintWriter(System.err);
|
||||||
GhidraScript foundScript = provider.getScriptInstance(scriptSourceFile, writer);
|
GhidraScript foundScript = provider.getScriptInstance(scriptSourceFile, errWriter);
|
||||||
|
|
||||||
if (propertiesFilePath != null) {
|
if (propertiesFilePath != null) {
|
||||||
// Get basename, assume that it ends in .java, since we've already covered the
|
// Get basename, assume that it ends in .java, since we've already covered the
|
||||||
|
|
|
@ -583,10 +583,11 @@ public class HeadlessAnalyzer {
|
||||||
srcFile != null ? srcFile.getAbsolutePath() : (script.getClass().getName() + ".class");
|
srcFile != null ? srcFile.getAbsolutePath() : (script.getClass().getName() + ".class");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
PrintWriter writer = new PrintWriter(System.out);
|
|
||||||
Msg.info(this, "SCRIPT: " + scriptName);
|
Msg.info(this, "SCRIPT: " + scriptName);
|
||||||
script.execute(scriptState, TaskMonitor.DUMMY, writer);
|
|
||||||
writer.flush();
|
// Execute the script, but don't directly write to stdout or stderr. The headless
|
||||||
|
// analyzer only uses the logging mechanism to get output to the user.
|
||||||
|
script.execute(scriptState, ScriptControls.NONE);
|
||||||
}
|
}
|
||||||
catch (Exception exc) {
|
catch (Exception exc) {
|
||||||
String logErrorMsg = "REPORT SCRIPT ERROR: ";
|
String logErrorMsg = "REPORT SCRIPT ERROR: ";
|
||||||
|
@ -908,8 +909,8 @@ public class HeadlessAnalyzer {
|
||||||
|
|
||||||
// GhidraScriptProvider case
|
// GhidraScriptProvider case
|
||||||
GhidraScriptProvider provider = GhidraScriptUtil.getProvider(currScriptFile);
|
GhidraScriptProvider provider = GhidraScriptUtil.getProvider(currScriptFile);
|
||||||
PrintWriter writer = new PrintWriter(System.out);
|
PrintWriter errWriter = new PrintWriter(System.err);
|
||||||
currScript = provider.getScriptInstance(currScriptFile, writer);
|
currScript = provider.getScriptInstance(currScriptFile, errWriter);
|
||||||
currScript.setScriptArgs(scriptArgs);
|
currScript.setScriptArgs(scriptArgs);
|
||||||
|
|
||||||
if (options.propertiesFilePaths.size() > 0) {
|
if (options.propertiesFilePaths.size() > 0) {
|
||||||
|
|
|
@ -405,7 +405,7 @@ public abstract class HeadlessScript extends GhidraScript {
|
||||||
"': unable to run this script type.");
|
"': unable to run this script type.");
|
||||||
}
|
}
|
||||||
|
|
||||||
GhidraScript script = provider.getScriptInstance(scriptSource, writer);
|
GhidraScript script = provider.getScriptInstance(scriptSource, errorWriter);
|
||||||
isHeadlessScript = script instanceof HeadlessScript ? true : false;
|
isHeadlessScript = script instanceof HeadlessScript ? true : false;
|
||||||
|
|
||||||
if (potentialPropertiesFileLocs.size() > 0) {
|
if (potentialPropertiesFileLocs.size() > 0) {
|
||||||
|
@ -423,7 +423,7 @@ public abstract class HeadlessScript extends GhidraScript {
|
||||||
|
|
||||||
script.setScriptArgs(scriptArguments);
|
script.setScriptArgs(scriptArguments);
|
||||||
|
|
||||||
script.execute(scriptState, monitor, writer);
|
script.execute(scriptState);
|
||||||
|
|
||||||
if (scriptState == state) {
|
if (scriptState == state) {
|
||||||
loadVariablesFromState();
|
loadVariablesFromState();
|
||||||
|
|
|
@ -557,18 +557,18 @@ public class TestEnv {
|
||||||
}
|
}
|
||||||
|
|
||||||
JavaScriptProvider scriptProvider = new JavaScriptProvider();
|
JavaScriptProvider scriptProvider = new JavaScriptProvider();
|
||||||
PrintWriter writer = new PrintWriter(System.out);
|
PrintWriter errWriter = new PrintWriter(System.err);
|
||||||
ResourceFile resourceFile = new ResourceFile(scriptFile);
|
ResourceFile resourceFile = new ResourceFile(scriptFile);
|
||||||
GhidraScript script = null;
|
GhidraScript script = null;
|
||||||
try {
|
try {
|
||||||
script = scriptProvider.getScriptInstance(resourceFile, writer);
|
script = scriptProvider.getScriptInstance(resourceFile, errWriter);
|
||||||
}
|
}
|
||||||
catch (GhidraScriptLoadException e) {
|
catch (GhidraScriptLoadException e) {
|
||||||
Msg.error(TestEnv.class, "Problem creating script", e);
|
Msg.error(TestEnv.class, "Problem creating script", e);
|
||||||
|
|
||||||
}
|
}
|
||||||
if (script == null) {
|
if (script == null) {
|
||||||
writer.flush();
|
errWriter.flush();
|
||||||
throw new RuntimeException("Failed to compile script " + scriptFile.getAbsolutePath());
|
throw new RuntimeException("Failed to compile script " + scriptFile.getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1610,16 +1610,14 @@ public abstract class AbstractGhidraScriptMgrPluginTest
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class SpyConsole extends ConsoleComponentProvider {
|
protected class SpyConsole extends ConsoleComponentProvider {
|
||||||
protected StringBuffer apiBuffer;
|
|
||||||
|
|
||||||
protected StringWriter outBuffer = new StringWriter();
|
protected StringWriter outBuffer = new StringWriter();
|
||||||
protected StringWriter errBuffer = new StringWriter();
|
protected StringWriter errBuffer = new StringWriter();
|
||||||
protected PrintWriter out = new PrintWriter(outBuffer);
|
protected PrintWriter out = new PrintWriter(outBuffer, true);
|
||||||
protected PrintWriter err = new PrintWriter(errBuffer);
|
protected PrintWriter err = new PrintWriter(errBuffer, true);
|
||||||
|
|
||||||
SpyConsole() {
|
SpyConsole() {
|
||||||
super(plugin.getTool(), "Spy Console");
|
super(plugin.getTool(), "Spy Console");
|
||||||
this.apiBuffer = new StringBuffer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1633,25 +1631,24 @@ public abstract class AbstractGhidraScriptMgrPluginTest
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
apiBuffer = new StringBuffer();
|
|
||||||
outBuffer = new StringWriter();
|
outBuffer = new StringWriter();
|
||||||
errBuffer = new StringWriter();
|
errBuffer = new StringWriter();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void println(String msg) {
|
public void println(String msg) {
|
||||||
apiBuffer.append(msg).append('\n');
|
out.println(msg);
|
||||||
Msg.trace(this, "Spy Script Console - println(): " + msg);
|
Msg.trace(this, "Spy Script Console - println(): " + msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addMessage(String originator, String msg) {
|
public void addMessage(String originator, String msg) {
|
||||||
apiBuffer.append(msg).append('\n');
|
out.println(msg);
|
||||||
Msg.trace(this, "Spy Script Console - addMessage(): " + msg);
|
Msg.trace(this, "Spy Script Console - addMessage(): " + msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
String getApiOutput() {
|
String getApiOutput() {
|
||||||
return apiBuffer.toString();
|
return outBuffer.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,7 +118,7 @@ public class BundleStatusManagerTest extends AbstractGhidraScriptMgrPluginTest {
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
final String EXPECTED_OUTPUT =
|
final String EXPECTED_OUTPUT =
|
||||||
TEST_SCRIPT_NAME+".java> Running...\n" +
|
TEST_SCRIPT_NAME+".java> Running...\n" +
|
||||||
TEST_SCRIPT_NAME+".java> Hello from pack2.Klass2\n" +
|
"Hello from pack2.Klass2\n" +
|
||||||
TEST_SCRIPT_NAME+".java> Finished!\n";
|
TEST_SCRIPT_NAME+".java> Finished!\n";
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
final File dir1 = new File(getTestDirectoryPath() + "/test_scripts1");
|
final File dir1 = new File(getTestDirectoryPath() + "/test_scripts1");
|
||||||
|
|
|
@ -54,7 +54,7 @@ public class GhidraScriptMgrPlugin2Test extends AbstractGhidraScriptMgrPluginTes
|
||||||
|
|
||||||
String consoleText = getConsoleText();
|
String consoleText = getConsoleText();
|
||||||
assertTrue("ConsoleText was \"" + consoleText + "\".",
|
assertTrue("ConsoleText was \"" + consoleText + "\".",
|
||||||
consoleText.indexOf("> Hello World") >= 0);
|
consoleText.indexOf("Hello World") >= 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -100,7 +100,7 @@ public class GhidraScriptMgrPlugin3Test extends AbstractGhidraScriptMgrPluginTes
|
||||||
String scriptOutput = runSelectedScript(script.getName());
|
String scriptOutput = runSelectedScript(script.getName());
|
||||||
|
|
||||||
assertTrue("Script output not generated",
|
assertTrue("Script output not generated",
|
||||||
scriptOutput.contains("> new scripts are neato!"));
|
scriptOutput.contains("new scripts are neato!"));
|
||||||
assertFalse("Script output has value from previous test run - did script not get deleted?",
|
assertFalse("Script output has value from previous test run - did script not get deleted?",
|
||||||
scriptOutput.contains("Value == 3368601"));
|
scriptOutput.contains("Value == 3368601"));
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ public class GhidraScriptMgrPlugin3Test extends AbstractGhidraScriptMgrPluginTes
|
||||||
String updatedScriptOutput = runSelectedScript(script.getName());
|
String updatedScriptOutput = runSelectedScript(script.getName());
|
||||||
|
|
||||||
assertTrue("Script output not updated with new script contents - did recompile work?",
|
assertTrue("Script output not updated with new script contents - did recompile work?",
|
||||||
StringUtilities.containsAll(updatedScriptOutput, "> new scripts are neato!",
|
StringUtilities.containsAll(updatedScriptOutput, "new scripts are neato!",
|
||||||
"Value == 3368601"));
|
"Value == 3368601"));
|
||||||
|
|
||||||
deleteScriptThroughUI();
|
deleteScriptThroughUI();
|
||||||
|
|
|
@ -42,7 +42,6 @@ import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||||
import ghidra.test.TestEnv;
|
import ghidra.test.TestEnv;
|
||||||
import ghidra.util.task.TaskMonitor;
|
|
||||||
import utilities.util.FileUtilities;
|
import utilities.util.FileUtilities;
|
||||||
|
|
||||||
public class GhidraScriptAskMethodsTest extends AbstractGhidraHeadedIntegrationTest {
|
public class GhidraScriptAskMethodsTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
@ -902,7 +901,7 @@ public class GhidraScriptAskMethodsTest extends AbstractGhidraHeadedIntegrationT
|
||||||
// test stub
|
// test stub
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
script.set(state, TaskMonitor.DUMMY, null);
|
script.set(state, ScriptControls.NONE);
|
||||||
|
|
||||||
URL url = GhidraScriptTest.class.getResource("GhidraScriptAsk.properties");
|
URL url = GhidraScriptTest.class.getResource("GhidraScriptAsk.properties");
|
||||||
assertNotNull("Test cannot run without properties file!", url);
|
assertNotNull("Test cannot run without properties file!", url);
|
||||||
|
|
|
@ -31,7 +31,6 @@ import ghidra.program.model.scalar.Scalar;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.test.*;
|
import ghidra.test.*;
|
||||||
import ghidra.util.task.TaskMonitor;
|
|
||||||
|
|
||||||
public class GhidraScriptRealProgramTest extends AbstractGhidraHeadedIntegrationTest {
|
public class GhidraScriptRealProgramTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
|
@ -399,7 +398,7 @@ public class GhidraScriptRealProgramTest extends AbstractGhidraHeadedIntegration
|
||||||
// test stub
|
// test stub
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
script.set(state, TaskMonitor.DUMMY, null);
|
script.set(state, ScriptControls.NONE);
|
||||||
return script;
|
return script;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,6 @@ import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||||
import ghidra.test.TestEnv;
|
import ghidra.test.TestEnv;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
|
||||||
|
|
||||||
public class GhidraScriptTest extends AbstractGhidraHeadedIntegrationTest {
|
public class GhidraScriptTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
|
@ -773,7 +772,7 @@ public class GhidraScriptTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
// test stub
|
// test stub
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
script.set(state, TaskMonitor.DUMMY, null);
|
script.set(state, ScriptControls.NONE);
|
||||||
return script;
|
return script;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -329,8 +329,8 @@ public class ShowConstantUse extends GhidraScript {
|
||||||
ResourceFile scriptSource = GhidraScriptUtil.findScriptByName(name);
|
ResourceFile scriptSource = GhidraScriptUtil.findScriptByName(name);
|
||||||
if (scriptSource != null) {
|
if (scriptSource != null) {
|
||||||
GhidraScriptProvider provider = GhidraScriptUtil.getProvider(scriptSource);
|
GhidraScriptProvider provider = GhidraScriptUtil.getProvider(scriptSource);
|
||||||
GhidraScript script = provider.getScriptInstance(scriptSource, writer);
|
GhidraScript script = provider.getScriptInstance(scriptSource, errorWriter);
|
||||||
script.execute(scriptState, monitor, writer);
|
script.execute(scriptState);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,7 @@ import java.nio.file.Path;
|
||||||
|
|
||||||
import docking.widgets.filechooser.GhidraFileChooser;
|
import docking.widgets.filechooser.GhidraFileChooser;
|
||||||
import docking.widgets.filechooser.GhidraFileChooserMode;
|
import docking.widgets.filechooser.GhidraFileChooserMode;
|
||||||
import ghidra.app.script.GhidraScript;
|
import ghidra.app.script.*;
|
||||||
import ghidra.app.script.GhidraState;
|
|
||||||
import ghidra.app.services.ConsoleService;
|
import ghidra.app.services.ConsoleService;
|
||||||
import ghidra.framework.options.ToolOptions;
|
import ghidra.framework.options.ToolOptions;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
|
@ -72,7 +71,8 @@ public class RunPCodeExportScriptTask extends Task {
|
||||||
script.setScriptArgs(new String[] { facts_directory });
|
script.setScriptArgs(new String[] { facts_directory });
|
||||||
|
|
||||||
console.addMessage(scriptName, "Running...");
|
console.addMessage(scriptName, "Running...");
|
||||||
script.execute(currentState, monitor, console.getStdOut());
|
script.execute(currentState,
|
||||||
|
new ScriptControls(console.getStdOut(), console.getStdErr(), false, monitor));
|
||||||
console.addMessage(scriptName, "Finished!");
|
console.addMessage(scriptName, "Finished!");
|
||||||
}
|
}
|
||||||
catch (CancelledException e) {
|
catch (CancelledException e) {
|
||||||
|
|
|
@ -34,6 +34,7 @@ import ghidra.app.plugin.ProgramPlugin;
|
||||||
import ghidra.app.plugin.core.console.CodeCompletion;
|
import ghidra.app.plugin.core.console.CodeCompletion;
|
||||||
import ghidra.app.plugin.core.interpreter.*;
|
import ghidra.app.plugin.core.interpreter.*;
|
||||||
import ghidra.app.script.GhidraState;
|
import ghidra.app.script.GhidraState;
|
||||||
|
import ghidra.app.script.ScriptControls;
|
||||||
import ghidra.framework.options.OptionsChangeListener;
|
import ghidra.framework.options.OptionsChangeListener;
|
||||||
import ghidra.framework.options.ToolOptions;
|
import ghidra.framework.options.ToolOptions;
|
||||||
import ghidra.framework.plugintool.PluginInfo;
|
import ghidra.framework.plugintool.PluginInfo;
|
||||||
|
@ -232,7 +233,7 @@ public class JythonPlugin extends ProgramPlugin
|
||||||
interactiveScript.set(
|
interactiveScript.set(
|
||||||
new GhidraState(tool, tool.getProject(), getCurrentProgram(), getProgramLocation(),
|
new GhidraState(tool, tool.getProject(), getCurrentProgram(), getProgramLocation(),
|
||||||
getProgramSelection(), getProgramHighlight()),
|
getProgramSelection(), getProgramHighlight()),
|
||||||
interactiveTaskMonitor, new PrintWriter(getConsole().getStdOut()));
|
new ScriptControls(console, interactiveTaskMonitor));
|
||||||
interpreter.injectScriptHierarchy(interactiveScript);
|
interpreter.injectScriptHierarchy(interactiveScript);
|
||||||
interactiveTaskMonitor = new JythonInteractiveTaskMonitor(console.getStdOut());
|
interactiveTaskMonitor = new JythonInteractiveTaskMonitor(console.getStdOut());
|
||||||
|
|
||||||
|
@ -288,7 +289,7 @@ public class JythonPlugin extends ProgramPlugin
|
||||||
interactiveScript.set(
|
interactiveScript.set(
|
||||||
new GhidraState(tool, tool.getProject(), currentProgram, currentLocation,
|
new GhidraState(tool, tool.getProject(), currentProgram, currentLocation,
|
||||||
currentSelection, currentHighlight),
|
currentSelection, currentHighlight),
|
||||||
interactiveTaskMonitor, console.getOutWriter());
|
new ScriptControls(console, interactiveTaskMonitor));
|
||||||
|
|
||||||
return interpreter.getCommandCompletions(cmd, includeBuiltins, caretPos);
|
return interpreter.getCommandCompletions(cmd, includeBuiltins, caretPos);
|
||||||
}
|
}
|
||||||
|
@ -377,7 +378,7 @@ public class JythonPlugin extends ProgramPlugin
|
||||||
}
|
}
|
||||||
|
|
||||||
public JythonInteractiveTaskMonitor(OutputStream stdout) {
|
public JythonInteractiveTaskMonitor(OutputStream stdout) {
|
||||||
this(new PrintWriter(stdout));
|
this(new PrintWriter(stdout, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -16,14 +16,15 @@
|
||||||
package ghidra.jython;
|
package ghidra.jython;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import org.python.core.PyException;
|
import org.python.core.PyException;
|
||||||
|
|
||||||
import db.Transaction;
|
import db.Transaction;
|
||||||
import generic.jar.ResourceFile;
|
import generic.jar.ResourceFile;
|
||||||
|
import ghidra.app.plugin.core.interpreter.InterpreterConsole;
|
||||||
import ghidra.app.script.GhidraState;
|
import ghidra.app.script.GhidraState;
|
||||||
|
import ghidra.app.script.ScriptControls;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
@ -59,6 +60,7 @@ class JythonPluginExecutionThread extends Thread {
|
||||||
TaskMonitor interactiveTaskMonitor = plugin.getInteractiveTaskMonitor();
|
TaskMonitor interactiveTaskMonitor = plugin.getInteractiveTaskMonitor();
|
||||||
JythonScript interactiveScript = plugin.getInteractiveScript();
|
JythonScript interactiveScript = plugin.getInteractiveScript();
|
||||||
Program program = plugin.getCurrentProgram();
|
Program program = plugin.getCurrentProgram();
|
||||||
|
InterpreterConsole console = plugin.getConsole();
|
||||||
|
|
||||||
// Setup transaction for the execution.
|
// Setup transaction for the execution.
|
||||||
try (Transaction tx = program != null ? program.openTransaction("Jython command") : null) {
|
try (Transaction tx = program != null ? program.openTransaction("Jython command") : null) {
|
||||||
|
@ -69,7 +71,7 @@ class JythonPluginExecutionThread extends Thread {
|
||||||
interactiveScript.set(
|
interactiveScript.set(
|
||||||
new GhidraState(tool, tool.getProject(), program, plugin.getProgramLocation(),
|
new GhidraState(tool, tool.getProject(), program, plugin.getProgramLocation(),
|
||||||
plugin.getProgramSelection(), plugin.getProgramHighlight()),
|
plugin.getProgramSelection(), plugin.getProgramHighlight()),
|
||||||
interactiveTaskMonitor, new PrintWriter(plugin.getConsole().getStdOut()));
|
new ScriptControls(console, interactiveTaskMonitor));
|
||||||
|
|
||||||
// Execute the command
|
// Execute the command
|
||||||
moreInputWanted.set(false);
|
moreInputWanted.set(false);
|
||||||
|
@ -81,14 +83,13 @@ class JythonPluginExecutionThread extends Thread {
|
||||||
plugin.reset();
|
plugin.reset();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
plugin.getConsole()
|
console.getErrWriter()
|
||||||
.getErrWriter()
|
|
||||||
.println(
|
.println(
|
||||||
"Suppressing exception: " + PyException.exceptionClassName(pye.type));
|
"Suppressing exception: " + PyException.exceptionClassName(pye.type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (StackOverflowError soe) {
|
catch (StackOverflowError soe) {
|
||||||
plugin.getConsole().getErrWriter().println("Stack overflow!");
|
console.getErrWriter().println("Stack overflow!");
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
interactiveScript.end(false); // end any transactions the script may have started
|
interactiveScript.end(false); // end any transactions the script may have started
|
||||||
|
|
|
@ -62,7 +62,7 @@ public class JythonScript extends GhidraScript {
|
||||||
ResourceFile scriptSource = GhidraScriptUtil.findScriptByName(scriptName);
|
ResourceFile scriptSource = GhidraScriptUtil.findScriptByName(scriptName);
|
||||||
if (scriptSource != null) {
|
if (scriptSource != null) {
|
||||||
GhidraScriptProvider provider = GhidraScriptUtil.getProvider(scriptSource);
|
GhidraScriptProvider provider = GhidraScriptUtil.getProvider(scriptSource);
|
||||||
GhidraScript ghidraScript = provider.getScriptInstance(scriptSource, writer);
|
GhidraScript ghidraScript = provider.getScriptInstance(scriptSource, errorWriter);
|
||||||
if (ghidraScript == null) {
|
if (ghidraScript == null) {
|
||||||
throw new IllegalArgumentException("Script does not exist: " + scriptName);
|
throw new IllegalArgumentException("Script does not exist: " + scriptName);
|
||||||
}
|
}
|
||||||
|
@ -72,12 +72,12 @@ public class JythonScript extends GhidraScript {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ghidraScript instanceof JythonScript) {
|
if (ghidraScript instanceof JythonScript) {
|
||||||
ghidraScript.set(scriptState, monitor, writer);
|
ghidraScript.set(scriptState);
|
||||||
JythonScript jythonScript = (JythonScript) ghidraScript;
|
JythonScript jythonScript = (JythonScript) ghidraScript;
|
||||||
interpreter.execFile(jythonScript.getSourceFile(), jythonScript);
|
interpreter.execFile(jythonScript.getSourceFile(), jythonScript);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ghidraScript.execute(scriptState, monitor, writer);
|
ghidraScript.execute(scriptState);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scriptState == state) {
|
if (scriptState == state) {
|
||||||
|
|
|
@ -25,8 +25,7 @@ import org.junit.*;
|
||||||
import generic.jar.ResourceFile;
|
import generic.jar.ResourceFile;
|
||||||
import ghidra.app.plugin.core.console.ConsolePlugin;
|
import ghidra.app.plugin.core.console.ConsolePlugin;
|
||||||
import ghidra.app.plugin.core.osgi.BundleHost;
|
import ghidra.app.plugin.core.osgi.BundleHost;
|
||||||
import ghidra.app.script.GhidraScriptUtil;
|
import ghidra.app.script.*;
|
||||||
import ghidra.app.script.GhidraState;
|
|
||||||
import ghidra.app.services.ConsoleService;
|
import ghidra.app.services.ConsoleService;
|
||||||
import ghidra.framework.Application;
|
import ghidra.framework.Application;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
|
@ -128,7 +127,7 @@ public class JythonScriptTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
JythonScriptProvider scriptProvider = new JythonScriptProvider();
|
JythonScriptProvider scriptProvider = new JythonScriptProvider();
|
||||||
PrintWriter writer = new PrintWriter(new ByteArrayOutputStream());
|
PrintWriter writer = new PrintWriter(new ByteArrayOutputStream());
|
||||||
JythonScript script = (JythonScript) scriptProvider.getScriptInstance(scriptFile, writer);
|
JythonScript script = (JythonScript) scriptProvider.getScriptInstance(scriptFile, writer);
|
||||||
script.set(state, TaskMonitor.DUMMY, writer);
|
script.set(state, new ScriptControls(writer, writer, TaskMonitor.DUMMY));
|
||||||
script.run();
|
script.run();
|
||||||
|
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
|
@ -93,9 +93,10 @@ public class WindowsResourceReferenceAnalyzer extends AbstractAnalyzer {
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintWriter writer = getOutputMsgStream(tool);
|
PrintWriter writer = getOutputMsgStream(tool);
|
||||||
|
PrintWriter errWriter = getErrorMsgStream(tool);
|
||||||
|
|
||||||
GhidraScript script = provider.getScriptInstance(sourceFile, writer);
|
GhidraScript script = provider.getScriptInstance(sourceFile, errWriter);
|
||||||
script.set(state, monitor, writer);
|
script.set(state, new ScriptControls(writer, errWriter, monitor));
|
||||||
|
|
||||||
// This code was added so the analyzer won't print script messages to console
|
// This code was added so the analyzer won't print script messages to console
|
||||||
// This also adds the ability to pass the option to add or not add bookmarks to the script
|
// This also adds the ability to pass the option to add or not add bookmarks to the script
|
||||||
|
@ -141,6 +142,16 @@ public class WindowsResourceReferenceAnalyzer extends AbstractAnalyzer {
|
||||||
return new PrintWriter(System.out);
|
return new PrintWriter(System.out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PrintWriter getErrorMsgStream(PluginTool tool) {
|
||||||
|
if (tool != null) {
|
||||||
|
ConsoleService console = tool.getService(ConsoleService.class);
|
||||||
|
if (console != null) {
|
||||||
|
return console.getStdErr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new PrintWriter(System.err);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean removed(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
|
public boolean removed(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
|
|
|
@ -22,6 +22,7 @@ import ghidra.app.plugin.PluginCategoryNames;
|
||||||
import ghidra.app.plugin.ProgramPlugin;
|
import ghidra.app.plugin.ProgramPlugin;
|
||||||
import ghidra.app.plugin.core.interpreter.InterpreterPanelService;
|
import ghidra.app.plugin.core.interpreter.InterpreterPanelService;
|
||||||
import ghidra.app.script.GhidraState;
|
import ghidra.app.script.GhidraState;
|
||||||
|
import ghidra.app.script.ScriptControls;
|
||||||
import ghidra.framework.plugintool.PluginInfo;
|
import ghidra.framework.plugintool.PluginInfo;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.framework.plugintool.util.PluginStatus;
|
import ghidra.framework.plugintool.util.PluginStatus;
|
||||||
|
@ -57,7 +58,7 @@ public class PyGhidraPlugin extends ProgramPlugin {
|
||||||
super(tool);
|
super(tool);
|
||||||
GhidraState state = new GhidraState(tool, tool.getProject(), null, null, null, null);
|
GhidraState state = new GhidraState(tool, tool.getProject(), null, null, null, null);
|
||||||
// use the copy constructor so this state doesn't fire plugin events
|
// use the copy constructor so this state doesn't fire plugin events
|
||||||
script.set(new GhidraState(state), null, null);
|
script.set(new GhidraState(state), ScriptControls.NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -86,13 +86,13 @@ public final class PyGhidraScriptProvider extends AbstractPythonScriptProvider {
|
||||||
"currentAddress", "currentLocation", "currentSelection",
|
"currentAddress", "currentLocation", "currentSelection",
|
||||||
"currentHighlight", "currentProgram", "monitor",
|
"currentHighlight", "currentProgram", "monitor",
|
||||||
"potentialPropertiesFileLocs", "propertiesFileParams",
|
"potentialPropertiesFileLocs", "propertiesFileParams",
|
||||||
"sourceFile", "state", "writer"
|
"sourceFile", "state", "writer", "errorWriter"
|
||||||
},
|
},
|
||||||
types = {
|
types = {
|
||||||
Address.class, ProgramLocation.class, ProgramSelection.class,
|
Address.class, ProgramLocation.class, ProgramSelection.class,
|
||||||
ProgramSelection.class, Program.class, TaskMonitor.class,
|
ProgramSelection.class, Program.class, TaskMonitor.class,
|
||||||
List.class, GhidraScriptProperties.class,
|
List.class, GhidraScriptProperties.class,
|
||||||
ResourceFile.class, GhidraState.class, PrintWriter.class
|
ResourceFile.class, GhidraState.class, PrintWriter.class, PrintWriter.class
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
final static class PyGhidraGhidraScript extends GhidraScript
|
final static class PyGhidraGhidraScript extends GhidraScript
|
||||||
|
@ -120,13 +120,13 @@ public final class PyGhidraScriptProvider extends AbstractPythonScriptProvider {
|
||||||
"currentAddress", "currentLocation", "currentSelection",
|
"currentAddress", "currentLocation", "currentSelection",
|
||||||
"currentHighlight", "currentProgram", "monitor",
|
"currentHighlight", "currentProgram", "monitor",
|
||||||
"potentialPropertiesFileLocs", "propertiesFileParams",
|
"potentialPropertiesFileLocs", "propertiesFileParams",
|
||||||
"sourceFile", "state", "writer"
|
"sourceFile", "state", "writer", "errorWriter"
|
||||||
},
|
},
|
||||||
types = {
|
types = {
|
||||||
Address.class, ProgramLocation.class, ProgramSelection.class,
|
Address.class, ProgramLocation.class, ProgramSelection.class,
|
||||||
ProgramSelection.class, Program.class, TaskMonitor.class,
|
ProgramSelection.class, Program.class, TaskMonitor.class,
|
||||||
List.class, GhidraScriptProperties.class,
|
List.class, GhidraScriptProperties.class,
|
||||||
ResourceFile.class, GhidraState.class, PrintWriter.class
|
ResourceFile.class, GhidraState.class, PrintWriter.class, PrintWriter.class
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
final static class PyGhidraHeadlessScript extends HeadlessScript
|
final static class PyGhidraHeadlessScript extends HeadlessScript
|
||||||
|
|
|
@ -17,8 +17,7 @@ package ghidra.pyghidra.interpreter;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
import ghidra.app.script.GhidraScript;
|
import ghidra.app.script.*;
|
||||||
import ghidra.app.script.GhidraState;
|
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
|
@ -86,6 +85,6 @@ public final class InterpreterGhidraScript extends GhidraScript {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void set(GhidraState state, PrintWriter writer) {
|
public void set(GhidraState state, PrintWriter writer) {
|
||||||
set(state, new InterpreterTaskMonitor(writer), writer);
|
set(state, new ScriptControls(writer, writer, new InterpreterTaskMonitor(writer)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue