refactor(ghidra): give function boundary scans one owner

This commit is contained in:
morluto committed 2026-10-15 06:25:02 +08:00
1 parent a004061abc
commit 225f26a5f8
1 file changed
+41 -37
+41 -37
View File
@@ -934,7 +934,7 @@ public final class ReaGhidraBridge extends HeadlessScript {
String value = decompiledText(decompile(function)); String value = decompiledText(decompile(function));
JsonObject result = functionObservation( JsonObject result = functionObservation(
value == null ? JsonNull.INSTANCE : GSON.toJsonTree(value), value == null ? JsonNull.INSTANCE : GSON.toJsonTree(value),
noReturnCallLimitations( functionBoundaryLimitations(
function, function,
currentProgram.getListing().getInstructions(function.getBody(), true) currentProgram.getListing().getInstructions(function.getBody(), true)
) )
@@ -1027,7 +1027,7 @@ public final class ReaGhidraBridge extends HeadlessScript {
InstructionScan scan = scanInstructions(function, Integer.MAX_VALUE); InstructionScan scan = scanInstructions(function, Integer.MAX_VALUE);
return functionObservation( return functionObservation(
GSON.toJsonTree(renderAssembly(scan.instructions)), GSON.toJsonTree(renderAssembly(scan.instructions)),
noReturnCallLimitations(function, scan.instructions) functionBoundaryLimitations(function, scan.instructions)
); );
} }
@@ -1046,7 +1046,7 @@ public final class ReaGhidraBridge extends HeadlessScript {
limitations.add( limitations.add(
"The fast path does not invoke the decompiler or scan whole-program names and strings." "The fast path does not invoke the decompiler or scan whole-program names and strings."
); );
List<String> boundaryLimitations = noReturnCallLimitations(function, scan.instructions); List<String> boundaryLimitations = functionBoundaryLimitations(function, scan.instructions);
for (String limitation : boundaryLimitations) limitations.add(limitation); for (String limitation : boundaryLimitations) limitations.add(limitation);
JsonObject result = new JsonObject(); JsonObject result = new JsonObject();
result.add("procedure", procedureIdentity(function)); result.add("procedure", procedureIdentity(function));
@@ -1069,7 +1069,7 @@ public final class ReaGhidraBridge extends HeadlessScript {
result.add(canonicalAddress(item.getEntryPoint())); result.add(canonicalAddress(item.getEntryPoint()));
} }
if (callers) { if (callers) {
JsonObject observation = functionObservation(result, noReturnCallLimitations(function, JsonObject observation = functionObservation(result, functionBoundaryLimitations(function,
currentProgram.getListing().getInstructions(function.getBody(), true) currentProgram.getListing().getInstructions(function.getBody(), true)
)); ));
observation.add("relationship_coverage", callRelationshipCoverage(null, observation.add("relationship_coverage", callRelationshipCoverage(null,
@@ -1099,7 +1099,7 @@ public final class ReaGhidraBridge extends HeadlessScript {
result.add("classification", functionClassification(function)); result.add("classification", functionClassification(function));
return functionObservation( return functionObservation(
result, result,
noReturnCallLimitations( functionBoundaryLimitations(
function, function,
currentProgram.getListing().getInstructions(function.getBody(), true) currentProgram.getListing().getInstructions(function.getBody(), true)
) )
@@ -1140,7 +1140,7 @@ public final class ReaGhidraBridge extends HeadlessScript {
unresolvedCalls = calls.unresolvedCalls(); unresolvedCalls = calls.unresolvedCalls();
limitations = calls.limitations(); limitations = calls.limitations();
} else { } else {
limitations = noReturnCallLimitations( limitations = functionBoundaryLimitations(
function, function,
currentProgram.getListing().getInstructions(function.getBody(), true) currentProgram.getListing().getInstructions(function.getBody(), true)
); );
@@ -3441,51 +3441,27 @@ public final class ReaGhidraBridge extends HeadlessScript {
return omitted[0]; return omitted[0];
} }
private List<String> noReturnCallLimitations( private List<String> functionBoundaryLimitations(
Function function, Iterable<Instruction> instructions) Function function, Iterable<Instruction> instructions)
throws Exception { throws Exception {
List<String> limitations = new ArrayList<>(); FunctionBoundaryLimitations boundary = new FunctionBoundaryLimitations(function);
Instruction beforePrevious = null; for (Instruction instruction : instructions) boundary.observe(instruction);
Instruction previous = null; return boundary.values();
for (Instruction instruction : instructions) {
monitor.checkCancelled();
String limitation = terminalCallLimitation(instruction);
if (limitation != null) limitations.add(limitation);
if (beforePrevious != null && previous != null) {
String seh = borlandSehHandlerLimitation(
function, beforePrevious, previous, instruction);
if (seh != null) limitations.add(seh);
}
beforePrevious = previous;
previous = instruction;
}
return limitations;
} }
private CallBoundaryObservation callBoundaryObservation( private CallBoundaryObservation callBoundaryObservation(
Function function, Iterable<Instruction> instructions, Set<Function> returnedCallees, Function function, Iterable<Instruction> instructions, Set<Function> returnedCallees,
boolean includeUnresolvedSites, List<Reference> observedReferences) boolean includeUnresolvedSites, List<Reference> observedReferences)
throws Exception { throws Exception {
List<String> limitations = new ArrayList<>(); FunctionBoundaryLimitations boundary = new FunctionBoundaryLimitations(function);
CallBoundaryReferences calls = new CallBoundaryReferences(returnedCallees, includeUnresolvedSites); CallBoundaryReferences calls = new CallBoundaryReferences(returnedCallees, includeUnresolvedSites);
Instruction beforePrevious = null;
Instruction previous = null;
if (observedReferences == null) visitReferences(function, "outgoing", calls::observe); if (observedReferences == null) visitReferences(function, "outgoing", calls::observe);
else for (Reference reference : observedReferences) { else for (Reference reference : observedReferences) {
monitor.checkCancelled(); monitor.checkCancelled();
calls.observe(reference); calls.observe(reference);
} }
for (Instruction instruction : instructions) { for (Instruction instruction : instructions) {
monitor.checkCancelled(); boundary.observe(instruction);
String limitation = terminalCallLimitation(instruction);
if (limitation != null) limitations.add(limitation);
if (beforePrevious != null && previous != null) {
String seh = borlandSehHandlerLimitation(
function, beforePrevious, previous, instruction);
if (seh != null) limitations.add(seh);
}
beforePrevious = previous;
previous = instruction;
if (!instruction.getFlowType().isCall()) continue; if (!instruction.getFlowType().isCall()) continue;
boolean destination = false; boolean destination = false;
for (Reference reference : instruction.getReferencesFrom()) { for (Reference reference : instruction.getReferencesFrom()) {
@@ -3499,10 +3475,38 @@ public final class ReaGhidraBridge extends HeadlessScript {
"Instruction decoder identifies a call but ReferenceManager supplies no call destination"); "Instruction decoder identifies a call but ReferenceManager supplies no call destination");
} }
} }
return new CallBoundaryObservation(List.copyOf(limitations), return new CallBoundaryObservation(boundary.values(),
returnedCallees == null ? null : calls.unrepresented, calls.unresolvedCalls()); returnedCallees == null ? null : calls.unrepresented, calls.unresolvedCalls());
} }
private final class FunctionBoundaryLimitations {
private final Function function;
private final List<String> limitations = new ArrayList<>();
private Instruction beforePrevious;
private Instruction previous;
private FunctionBoundaryLimitations(Function function) {
this.function = function;
}
private void observe(Instruction instruction) throws Exception {
monitor.checkCancelled();
String limitation = terminalCallLimitation(instruction);
if (limitation != null) limitations.add(limitation);
if (beforePrevious != null && previous != null) {
String seh = borlandSehHandlerLimitation(
function, beforePrevious, previous, instruction);
if (seh != null) limitations.add(seh);
}
beforePrevious = previous;
previous = instruction;
}
private List<String> values() {
return List.copyOf(limitations);
}
}
private String borlandSehHandlerLimitation( private String borlandSehHandlerLimitation(
Function function, Instruction handlerPush, Instruction framePush, Function function, Instruction handlerPush, Instruction framePush,
Instruction frameLink) { Instruction frameLink) {