How to Use Ghidra's Task Monitor and Progress Tracking in Scripts
Ghidra scripts report execution progress and handle cancellation by calling methods on the built-in TaskMonitor instance, such as initialize(), incrementProgress(), and checkCancelled().
The NationalSecurityAgency/ghidra repository provides a polymorphic TaskMonitor architecture that enables consistent progress tracking across GUI, headless, and console execution modes. By leveraging the monitor field provided by the GhidraScript base class, analysts can write responsive scripts that display progress bars in the GUI and run silently in batch operations without code changes.
Understanding the TaskMonitor Architecture
The framework centers on the ghidra.util.task.TaskMonitor interface, defined in Ghidra/Framework/Utility/src/main/java/ghidra/util/task/TaskMonitor.java. This contract specifies methods for progress initialization, incremental updates, status messaging, and cancellation detection.
Ghidra implements this interface through several layers:
-
TaskMonitor.DUMMY: A no-op implementation (backed by
StubTaskMonitor) injected during headless execution when no UI is available. -
ConsoleTaskMonitor: Outputs progress to standard output, utilized in testing and command-line utilities (
Ghidra/Framework/Generic/src/main/java/ghidra/util/task/ConsoleTaskMonitor.java). -
TaskMonitorComponent: A Swing component rendering visual progress bars and cancel buttons in the GUI (
Ghidra/Framework/Docking/src/main/java/ghidra/util/task/TaskMonitorComponent.java).
Script integration occurs through ghidra.app.script.GhidraScript (Ghidra/Features/Base/src/main/java/ghidra/app/script/GhidraScript.java). The base class declares a protected monitor field that the framework populates automatically via ScriptControls. For headless runs, GhidraScriptRunner (Ghidra/Features/Base/src/main/java/ghidra/app/util/headless/GhidraScriptRunner.java) constructs ScriptControls with TaskMonitor.DUMMY, ensuring scripts can call monitor methods without null checks.
Core Workflow for Progress Tracking
All Ghidra scripts follow a consistent pattern to implement user feedback and cancellation support.
Initialize the Monitor
Call monitor.initialize(totalWork) once at the beginning, passing the total number of work units. Pass -1 for indeterminate progress when the total scope is unknown.
Check for User Cancellation
Inside every significant loop, invoke monitor.checkCancelled(). According to the source code in TaskMonitor.java, this method throws CancelledException immediately when the user presses the cancel button in the GUI, allowing scripts to terminate cleanly and release resources.
Update Progress and Messages
Advance the progress bar using monitor.incrementProgress(amount) or set an absolute value with monitor.setProgress(value). Update the status line via monitor.setMessage("status text") to inform users of current operations.
Code Examples
Jython (Python) Script
Jython scripts access the pre-bound monitor variable, following the pattern demonstrated in Ghidra/Features/Jython/ghidra_scripts/ghidra_basics.py.
import time
# 1. Initialize for 10 steps
monitor.initialize(10)
for i in range(10):
# 2. Respond to cancellation
monitor.checkCancelled()
# Simulate work
time.sleep(0.5)
# 3. Update progress
monitor.incrementProgress(1)
# 4. Update status message
monitor.setMessage("Processing item %d of 10" % (i + 1))
Java Ghidra Script
Java scripts extend GhidraScript and access the inherited monitor field populated by the framework during execute().
public class MyAnalysisScript extends GhidraScript {
@Override
protected void run() throws Exception {
// Initialize for 5 operations
monitor.initialize(5);
for (int i = 0; i < 5; i++) {
// Throw CancelledException if user pressed Cancel
monitor.checkCancelled();
// Perform work
doWork(i);
// Update progress and message
monitor.incrementProgress(1);
monitor.setMessage("Finished step " + (i + 1) + " of 5");
}
}
private void doWork(int step) {
// Implementation-specific analysis
}
}
Headless Execution
When launched from the command line, GhidraScriptRunner instantiates TaskMonitor.DUMMY:
ScriptControls controls = new ScriptControls(System.out, System.err, TaskMonitor.DUMMY);
script.execute(state, controls);
The same script code works without modification; progress calls become no-ops, and checkCancelled() never throws, enabling batch processing without UI dependencies.
Console-Based Monitoring
For tests or command-line tools requiring visibility, explicitly instantiate ConsoleTaskMonitor:
TaskMonitor monitor = new ConsoleTaskMonitor();
monitor.initialize(100);
for (int i = 0; i < 100; i++) {
monitor.checkCancelled(); // Prints cancellation status on Ctrl-C
// ... work ...
monitor.incrementProgress(1);
monitor.setMessage(" processed " + i);
}
Summary
-
TaskMonitor interface: Core contract defined in
TaskMonitor.javaprovidinginitialize(),incrementProgress(),setMessage(), andcheckCancelled()methods. -
Automatic injection:
GhidraScriptbase class provides themonitorfield;GhidraScriptRunnerhandles headless setup withTaskMonitor.DUMMY. -
Cancellation handling:
checkCancelled()throwsCancelledExceptionwhen users press the cancel button, enabling graceful termination. -
Cross-mode compatibility: Identical script code operates in GUI mode (visual progress bar via
TaskMonitorComponent) and headless mode (silent operation viaTaskMonitor.DUMMY). -
Console alternative:
ConsoleTaskMonitorenables text-based progress reporting in terminal environments.
Frequently Asked Questions
What happens if I don't use the TaskMonitor in my Ghidra script?
The script executes normally but provides no progress feedback or cancellation capability. In GUI mode, the progress bar remains empty; in headless mode, the monitor operates as a no-op. Long-running operations cannot be interrupted by users, forcing manual process termination.
How do I make a Ghidra script cancellable by users?
Insert monitor.checkCancelled() inside every major loop or long-running operation. As implemented in the source code, this method detects the cancel button state and throws CancelledException immediately, terminating the script execution cleanly and allowing resource cleanup.
Can I use the same progress tracking code for GUI and headless execution?
Yes. The polymorphic design ensures TaskMonitor.DUMMY (injected by GhidraScriptRunner.java for headless runs) implements the full TaskMonitor interface. Progress calls execute as silent no-ops, while checkCancelled() returns normally without throwing, allowing identical scripts to run in both environments without conditional logic.
Where is the TaskMonitor interface defined in the Ghidra source code?
The core interface resides at Ghidra/Framework/Utility/src/main/java/ghidra/util/task/TaskMonitor.java. The Swing GUI implementation is located at Ghidra/Framework/Docking/src/main/java/ghidra/util/task/TaskMonitorComponent.java, while console output handling is implemented in Ghidra/Framework/Generic/src/main/java/ghidra/util/task/ConsoleTaskMonitor.java.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →