70 lines
3.0 KiB
Java
70 lines
3.0 KiB
Java
// 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<Address, Function> 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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|