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