Skip to content

Conversation

@itxsamad1
Copy link

Summary

  • Adds three self-contained Base scripts for exporting analysis results:
    • ExportFunctionMetricsToJson: per-function metrics to JSON with a summary section and optional selection/highlight filtering.
    • ExportFunctionMetricsToCsv: same metrics to CSV with a stable header.
    • ExportFunctionCallGraphToDot: exports the program function call graph to Graphviz DOT; supports selection/highlight filtering.

Motivation

  • Provide lightweight, automation-friendly exports for CI, baselining, and external tooling without changing core UI or build.
  • Complements existing scripts (e.g., ComputeCyclomaticComplexity) with batch reporting and a simple call graph exporter.

Details

  • Metrics include:
    • identity: name, entry, namespace
    • body stats: size_bytes (address count), address_ranges, instruction_count, basic_blocks
    • complexity/interop: cyclomatic_complexity, parameters, locals
    • flags: external, thunk, variadic, inline, no_return, custom_storage
    • calling: stack_purge_size, calling_convention, callers, callees
    • types/signature: return_type, prototype, prototype_with_cc
  • Selection/highlight filtering limits output to functions intersecting the chosen scope.
  • Progress monitors update and respect cancellation; computation errors are logged and do not abort export.
  • DOT exporter labels nodes as functionName\nentryAddress and writes simple edges from callers to callees.

Usage

  • Run from Script Manager on an analyzed program:
    • ExportFunctionMetricsToJson → choose .json
    • ExportFunctionMetricsToCsv → choose .csv
    • ExportFunctionCallGraphToDot → choose .dot
  • Optional: select or highlight an address range before running to filter output.

Files Changed

  • Ghidra/Features/Base/ghidra_scripts/ExportFunctionMetricsToJson.java:1
  • Ghidra/Features/Base/ghidra_scripts/ExportFunctionMetricsToCsv.java:1
  • Ghidra/Features/Base/ghidra_scripts/ExportFunctionCallGraphToDot.java:1

How To Test

  • Open any program with analysis applied.
  • Optionally select a subset of code to test filtering.
  • Run each script; verify:
    • JSON emits a valid document with program, functions[], and summary.
    • CSV imports cleanly (quoted header and fields).
    • DOT renders via Graphviz, e.g., dot -Tpng out.dot -o out.png, and reflects expected edges.

Scope / Compliance

  • No 3rd-party dependencies; no build system changes.
  • Small, focused scripts under Base ghidra_scripts.
  • Adheres to CONTRIBUTING guidance for small, utility-focused improvements.

Notes

  • size_bytes reports address count in the function body; address_ranges clarifies segmentation.
  • Locals are omitted for external functions.
  • DOT exporter keeps edges within selection when filtering is used.

Optional Checklist

  • Ran scripts on at least one sample program
  • Validated JSON structure and CSV header in common tools
  • Rendered DOT via Graphviz
  • Scoped PR to scripts only; no refactors or external jars

Copy link
Collaborator

@ryanmkurtz ryanmkurtz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would make more sense to add this functionality to the existing ExportFunctionInfoScript. GhidraScript.askChoices() could be used to choose the export format.

@ryanmkurtz ryanmkurtz added the Status: Waiting on customer Waiting for customer feedback label Oct 30, 2025
- Consolidated ExportFunctionMetricsToJson, ExportFunctionMetricsToCsv, and ExportFunctionCallGraphToDot into ExportFunctionInfoScript.java
- Added format selection using GhidraScript.askChoices() as requested in code review
- Users can now choose between: JSON (Simple), JSON (Detailed metrics), CSV (Detailed metrics), and DOT (Function call graph)
- All export formats support optional selection/highlight filtering
- Maintains backward compatibility with existing simple JSON export functionality
@itxsamad1
Copy link
Author

I think it would make more sense to add this functionality to the existing ExportFunctionInfoScript. GhidraScript.askChoices() could be used to choose the export format.

Hi @ryanmkurtz,

Thank you for the review! I've implemented your suggestion to consolidate the functionality into the existing ExportFunctionInfoScript.java.

Changes made:

  • Integrated all three export scripts into ExportFunctionInfoScript.java
  • Used GhidraScript.askChoices() to let users select the export format
  • Removed the three separate script files (ExportFunctionMetricsToJson, ExportFunctionMetricsToCsv, ExportFunctionCallGraphToDot)
  • Users can now choose between: JSON (Simple), JSON (Detailed metrics), CSV (Detailed metrics), and DOT (Function call graph)

All functionality has been preserved, including selection/highlight filtering and progress monitoring. Please let me know if there are any other changes needed!

@ryanmkurtz ryanmkurtz added Status: Triage Information is being gathered and removed Status: Waiting on customer Waiting for customer feedback labels Oct 31, 2025
@ryanmkurtz
Copy link
Collaborator

Thanks, I hope to review it next week.

@itxsamad1 itxsamad1 requested a review from ryanmkurtz November 2, 2025 15:19
@ryanmkurtz
Copy link
Collaborator

Apologies, I was away for a couple of weeks. I hope to actually review it this week.

monitor.incrementProgress(1);

String fEntry = f.getEntryPoint().toString();
idByEntry.computeIfAbsent(fEntry, k -> nextId++);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The compiler doesn't like nextId being modified within the lambda. This logic will have to change.

ExportFunctionInfoScript.java:435: error: local variables referenced from a lambda expression must be final or effectively final
			idByEntry.computeIfAbsent(fEntry, k -> nextId++);

continue;
}
String cEntry = callee.getEntryPoint().toString();
idByEntry.computeIfAbsent(cEntry, k -> nextId++);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ExportFunctionInfoScript.java:443: error: local variables referenced from a lambda expression must be final or effectively final
				idByEntry.computeIfAbsent(cEntry, k -> nextId++);

"Select the format for exporting function information:", formats, ExportFormat.JSON_SIMPLE);

// Determine file extension based on format
String extension;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable extension

}
}
catch (CancelledException ce) {
// Respect cancellation
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would just allow any CancelledExceptions to propagate out of the run() method, rather than trying to handle each one like this. You'd want the script to immediately stop running when cancel is clicked anyway.


// Instruction count
int instCount = 0;
for (Iterator<Instruction> insIt = listing.getInstructions(body, true); insIt.hasNext();) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should just be able to use a for-each style loop here (and elsewhere)

@ryanmkurtz ryanmkurtz added Status: Waiting on customer Waiting for customer feedback and removed Status: Triage Information is being gathered labels Nov 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants