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:

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.java providing initialize(), incrementProgress(), setMessage(), and checkCancelled() methods.

  • Automatic injection: GhidraScript base class provides the monitor field; GhidraScriptRunner handles headless setup with TaskMonitor.DUMMY.

  • Cancellation handling: checkCancelled() throws CancelledException when 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 via TaskMonitor.DUMMY).

  • Console alternative: ConsoleTaskMonitor enables 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →