Ghidra Tip 0x09: TaskMonitor

This article is based on the public release of Ghidra 11.2.

While scripts are generally used to automatically (and/or automagically) perform repeatable and mundane actions, that is not to say that their runtime cannot take a while. If the wrong script is started by accident, or if the chosen approach is too time consuming, the analyst might want to cancel the script. Ghidra allows one to cancel scripts, but some scripts seem to continue as if nothing happened.

From a technical standpoint that is correct: unless a script includes the cancellation check, nothing happens. Some scripts show the current action, and the total number of actions to be taken, in the graphical user interface to indicate the progress. All these actions are confined within the TaskMonitor object. Below, some examples are given with context, which shows how to improve the user-experience of a Ghidra script.

First, one needs to initialise the monitor object’s values. This object is accessible in the FlatAPI, meaning that no instance needs to be created as it is provided during runtime. The initialisation requires a maximum value, which is the total number of tasks to be completed with the given message. The message itself is the second argument.

int maximumValue = 999; //The total number of tasks to be completed
monitor.initialize(maximumValue, "Performing a long task!"); //Be descriptive yet succinct when describing the task at hand

Some tasks do not require updates. To initialise the monitor for them, either provide the value 1 and increment to complete it, or use setMessage(String message) instead.

String message = "This task does something that might take a while!";
monitor.setMessage(message); //Be descriptive yet succinct when describing the task at hand

Within a loop, the monitor needs to be incremented to provide the visual update. This will increase the current count. The current and maximum count are shown on the screen, along with the percentage. The percentage is the relative value of the current value compared to the maximum value.

monitor.increment();

Alternatively, one can increment the value by an arbitrary amount, if this is required.

long incrementAmount = 10L;
monitor.incrementProgress(incrementAmount);

The current progress value can be obtained using getProgress(), which will return a long with the respective value.

long progress = monitor.getProgress();

Within the loop of a long action, or in-between tasks which take a long(er) amount of time if there is no loop, one should call the Monitor’s isCancelled function. This function will return a boolean which indicates if the analyst cancelled the script prior to this function call.

boolean result = monitor.isCancelled()

If the script is cancelled, etiquette states that the script should shut down gracefully. Changes made needn’t be reverted per se, depending on the purpose and impact of the script.

The usage of increment over incrementProgress lies within the former’s function content. As shown below, it is a wrapper to increment the progress with one, but it first checks if the script is cancelled by the user. As such, using the increment call automatically includes the cancellation check.

checkCancelled();
incrementProgress(1);

The checkCancelled function will throw an CancelledException if the script has been cancelled. One can call this function at any point in time, as it is also exposed by the monitor. Putting the entire script or some parts of the script within a try-catch structure to handle the cancellation of the script makes it easy to stop quickly without too much overhead in code.


To contact me, you can e-mail me at [info][at][maxkersten][dot][nl], or DM me on BlueSky @maxkersten.nl.