/* ### * IP: GHIDRA * * 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. * See the License for the specific language governing permissions and * limitations under the License. */ // 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; public class PrintFunctionCallTreesScript extends GhidraScript { @Override protected void run() throws Exception { Function function = getCurrentFunction(); if (function == null) { println("Cursor is not in or on a function"); return; } printIncomingCalls(function); println("\n"); 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); } } // sort them by address List list = new ArrayList<>(callingFunctions); Collections.sort(list, (f1, f2) -> f1.getEntryPoint().compareTo(f2.getEntryPoint())); for (Function f : list) { println("Incoming Function Call: " + f.getName() + " @ " + f.getEntryPoint()); } } 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); } // sort them by address List list = new ArrayList<>(outgoingFunctions); Collections.sort(list, (f1, f2) -> f1.getEntryPoint().compareTo(f2.getEntryPoint())); for (Function f : list) { println("Outgoing Function Call: " + f.getName() + " @ " + f.getEntryPoint()); } } 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); } }