use monitor().isCancelled() to control Ghidra execution
Calls to monitor().isCancelled() can be used to stop execution if a user chooses to cancel a script run. This is especially important for long runs. Let's use monitor().isCancelled() where it makes sense to ensure a good UX.
Also, monitor().setProgress().
some strategies:
- we could pass callbacks to
find_capabilitiesand friends that are invoked e.g. after each function is matched. this way the callback could checkmonitor().isCancelled()upon each loop and raise an exception if necessary. likewise withsetProgress(). - we could check
isCancelled()from withinExtractor.get_function_features()which we can assume is invoked once per function. we could raise an exception if Ghidra wants to exit. this strategy would not be appropriate for updating progress, though. - what else?
(1) seems like the more robust design, though it will take a little work to thread this through. it'll also pollute the function signatures a bit, though we can provide default, empty callbacks so most callers don't have to do anything.
this infrastructure would also be used by the IDA extractor. because there are multiple extractors that need this functionality, it seems reasonable to investigate and implement.
@dataclass
class CapaAnalysisCallbacks:
on_analyze_function: Callable[...]
def find_capabilities(..., callbacks):
...
for function in extractor.get_functions():
callbacks.on_analyze_function(function)
...
def main(...):
...
if is_ghidra:
def on_ghidra_analyze_function(function_handle, index, total):
if monitor.isCancelled():
raise SystemExit(...)
monitor.setProgress(index, total)
callbacks = CapaAnalysisCallbacks(on_analyze_function=on_ghidra_analyze_function)
find_capabilities(..., callbacks)