// GhidraScript: decompile every caller of a function and print call-site context. // Usage: DecompileCallContexts.java 0x0063c0f0 [context-lines] import ghidra.app.decompiler.DecompInterface; import ghidra.app.decompiler.DecompileResults; import ghidra.app.script.GhidraScript; import ghidra.program.model.address.Address; import ghidra.program.model.listing.Function; import ghidra.program.model.symbol.Reference; import ghidra.program.model.symbol.ReferenceIterator; import java.util.LinkedHashMap; import java.util.Map; public class DecompileCallContexts extends GhidraScript { @Override public void run() throws Exception { String[] args = getScriptArgs(); if (args == null || args.length == 0) { printerr("DecompileCallContexts: needs a function address"); return; } Address target = toAddr(Long.decode(args[0])); Function targetFunction = getFunctionAt(target); if (targetFunction == null) { printerr("target is not a function"); return; } int context = args.length > 1 ? Integer.decode(args[1]) : 5; Map callers = new LinkedHashMap<>(); ReferenceIterator references = currentProgram.getReferenceManager().getReferencesTo(target); while (references.hasNext()) { Reference reference = references.next(); Function caller = getFunctionContaining(reference.getFromAddress()); if (caller != null) callers.put(caller.getEntryPoint(), caller); } DecompInterface decompiler = new DecompInterface(); decompiler.openProgram(currentProgram); String needle = targetFunction.getName(); for (Function caller : callers.values()) { if (monitor.isCancelled()) break; DecompileResults result = decompiler.decompileFunction(caller, 90, monitor); if (!result.decompileCompleted() || result.getDecompiledFunction() == null) continue; String[] lines = result.getDecompiledFunction().getC().split("\\R"); boolean[] selected = new boolean[lines.length]; for (int i = 0; i < lines.length; ++i) { if (!lines[i].contains(needle)) continue; for (int j = Math.max(0, i - context); j <= Math.min(lines.length - 1, i + context); ++j) { selected[j] = true; } } println("================================================================================"); println(caller.getEntryPoint() + " " + caller.getName(true)); boolean gap = false; for (int i = 0; i < lines.length; ++i) { if (selected[i]) { if (gap) println("..."); println(String.format("%5d %s", i + 1, lines[i])); gap = false; } else if (i > 0 && selected[i - 1]) { gap = true; } } } } }