From dadfaae8c9314ec181bbdb2b38701af73f777c01 Mon Sep 17 00:00:00 2001
From: James <49045138+ghidracadabra@users.noreply.github.com>
Date: Mon, 2 Dec 2024 08:39:14 -0500
Subject: [PATCH] GP-5104 get calling/called functions fixes
---
.../PrintFunctionCallTreesScript.java | 86 ++-----------------
.../program/database/function/FunctionDB.java | 66 +++++++-------
2 files changed, 40 insertions(+), 112 deletions(-)
diff --git a/Ghidra/Features/Base/ghidra_scripts/PrintFunctionCallTreesScript.java b/Ghidra/Features/Base/ghidra_scripts/PrintFunctionCallTreesScript.java
index a00d5ea8d2..385313ed7c 100644
--- a/Ghidra/Features/Base/ghidra_scripts/PrintFunctionCallTreesScript.java
+++ b/Ghidra/Features/Base/ghidra_scripts/PrintFunctionCallTreesScript.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -15,16 +15,11 @@
*/
// An example script that will print to the console, for a given function, all other functions
// that call it and all functions that it calls.
-//import ghidra.app.plugin.core.navigation.locationreferences.ReferenceUtils;
import java.util.*;
-import ghidra.app.plugin.core.navigation.locationreferences.ReferenceUtils;
import ghidra.app.script.GhidraScript;
-import ghidra.program.model.address.*;
-import ghidra.program.model.listing.*;
-import ghidra.program.model.symbol.*;
-import ghidra.program.util.FunctionSignatureFieldLocation;
-import ghidra.util.exception.CancelledException;
+import ghidra.program.model.listing.Function;
+import ghidra.program.model.listing.FunctionManager;
public class PrintFunctionCallTreesScript extends GhidraScript {
@@ -42,19 +37,9 @@ public class PrintFunctionCallTreesScript extends GhidraScript {
printOutgoingCalls(function);
}
- private void printIncomingCalls(Function function) throws CancelledException {
- Address functionAddress = function.getEntryPoint();
- FunctionSignatureFieldLocation location =
- new FunctionSignatureFieldLocation(function.getProgram(), functionAddress);
- Set
addresses = ReferenceUtils.getReferenceAddresses(location, monitor);
- FunctionManager functionManager = currentProgram.getFunctionManager();
- Set callingFunctions = new HashSet<>();
- for (Address fromAddress : addresses) {
- Function callerFunction = functionManager.getFunctionContaining(fromAddress);
- if (callerFunction != null) {
- callingFunctions.add(callerFunction);
- }
- }
+ private void printIncomingCalls(Function function) {
+
+ Set callingFunctions = function.getCallingFunctions(monitor);
// sort them by address
List list = new ArrayList<>(callingFunctions);
@@ -66,15 +51,8 @@ public class PrintFunctionCallTreesScript extends GhidraScript {
}
private void printOutgoingCalls(Function function) {
- AddressSetView functionBody = function.getBody();
- Set references = getReferencesFrom(currentProgram, functionBody);
- Set outgoingFunctions = new HashSet<>();
- FunctionManager functionManager = currentProgram.getFunctionManager();
- for (Reference reference : references) {
- Address toAddress = reference.getToAddress();
- Function calledFunction = functionManager.getFunctionAt(toAddress);
- maybeAddIncomingFunction(outgoingFunctions, reference, calledFunction);
- }
+
+ Set outgoingFunctions = function.getCalledFunctions(monitor);
// sort them by address
List list = new ArrayList<>(outgoingFunctions);
@@ -85,52 +63,6 @@ public class PrintFunctionCallTreesScript extends GhidraScript {
}
}
- private void maybeAddIncomingFunction(Set incomingFunctions, Reference reference,
- Function calledFunction) {
- if (calledFunction != null) {
- incomingFunctions.add(calledFunction);
- }
- else if (isCallReference(reference)) {
- // we have a call reference, but no function
- println("Outgoing function call with no function from " + reference.getFromAddress() +
- " to " + reference.getToAddress());
- }
- }
-
- private boolean isCallReference(Reference reference) {
- RefType type = reference.getReferenceType();
- if (type.isCall()) {
- return true;
- }
-
- if (type.isIndirect()) {
- Listing listing = currentProgram.getListing();
- Instruction instruction = listing.getInstructionAt(reference.getFromAddress());
- if (instruction != null) {
- FlowType flowType = instruction.getFlowType();
- return flowType.isCall();
- }
- }
-
- return false;
- }
-
- private Set getReferencesFrom(Program program, AddressSetView addresses) {
- Set set = new HashSet<>();
- ReferenceManager referenceManager = program.getReferenceManager();
- AddressIterator addressIterator = addresses.getAddresses(true);
- while (addressIterator.hasNext()) {
- Address address = addressIterator.next();
- Reference[] referencesFrom = referenceManager.getReferencesFrom(address);
- if (referencesFrom != null) {
- for (Reference reference : referencesFrom) {
- set.add(reference);
- }
- }
- }
- return set;
- }
-
private Function getCurrentFunction() {
FunctionManager functionManager = currentProgram.getFunctionManager();
return functionManager.getFunctionContaining(currentAddress);
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java
index ace0699cd5..45953238f4 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -2717,58 +2717,54 @@ public class FunctionDB extends DatabaseObject implements Function {
@Override
public Set getCallingFunctions(TaskMonitor monitor) {
monitor = TaskMonitor.dummyIfNull(monitor);
- Set set = new HashSet<>();
+ Set callers = new HashSet<>();
ReferenceIterator iter = program.getReferenceManager().getReferencesTo(getEntryPoint());
+
while (iter.hasNext()) {
if (monitor.isCancelled()) {
- return set;
+ break;
}
Reference reference = iter.next();
+ if (!reference.getReferenceType().isCall()) {
+ continue;
+ }
Address fromAddress = reference.getFromAddress();
Function callerFunction = manager.getFunctionContaining(fromAddress);
if (callerFunction != null) {
- set.add(callerFunction);
+ callers.add(callerFunction);
}
}
- return set;
+ return callers;
}
@Override
public Set getCalledFunctions(TaskMonitor monitor) {
monitor = TaskMonitor.dummyIfNull(monitor);
- Set set = new HashSet<>();
- Set references = getReferencesFromBody(monitor);
- for (Reference reference : references) {
- if (monitor.isCancelled()) {
- return set;
- }
- Address toAddress = reference.getToAddress();
- Function calledFunction = manager.getFunctionAt(toAddress);
- if (calledFunction != null) {
- set.add(calledFunction);
- }
- }
- return set;
- }
+ Set callees = new HashSet<>();
+ ReferenceManager refManager = program.getReferenceManager();
+ AddressRangeIterator rangeIter = getBody().getAddressRanges();
- private Set getReferencesFromBody(TaskMonitor monitor) {
- Set set = new HashSet<>();
- ReferenceManager referenceManager = program.getReferenceManager();
- AddressSetView addresses = getBody();
- AddressIterator addressIterator = addresses.getAddresses(true);
- while (addressIterator.hasNext()) {
- if (monitor.isCancelled()) {
- return set;
- }
- Address address = addressIterator.next();
- Reference[] referencesFrom = referenceManager.getReferencesFrom(address);
- if (referencesFrom != null) {
- for (Reference reference : referencesFrom) {
- set.add(reference);
+ while (rangeIter.hasNext()) {
+ AddressRange range = rangeIter.next();
+ ReferenceIterator refIter = refManager.getReferenceIterator(range.getMinAddress());
+ while (refIter.hasNext()) {
+ if (monitor.isCancelled()) {
+ return callees;
+ }
+ Reference ref = refIter.next();
+ if (!range.contains(ref.getFromAddress())) {
+ break; // exhausted all addresses in the AddressRange, check next AddressRange
+ }
+ if (!ref.getReferenceType().isCall()) {
+ continue; // reference is not a call, check next reference
+ }
+ Function callee = manager.getFunctionAt(ref.getToAddress());
+ if (callee != null) { // sanity check
+ callees.add(callee);
}
}
}
- return set;
+ return callees;
}
@Override