ghidra/Ghidra/Features/Decompiler/ghidra_scripts/ShowCCallsScript.java

252 lines
8.1 KiB
Java

/* ###
* 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.
*/
// Given a routine, show all the calls to that routine and their parameters.
// Place the cursor on a function (can be an external .dll function).
// Execute the script.
// The decompiler will be run on everything that calls the function at the cursor
// All calls to the function will display with their parameters to the function.
//
// This script assumes good flow, that switch stmts are good.
//
//@category Functions
import java.util.Iterator;
import ghidra.app.decompiler.*;
import ghidra.app.script.GhidraScript;
import ghidra.framework.options.ToolOptions;
import ghidra.framework.plugintool.util.OptionsService;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.*;
import ghidra.program.model.pcode.HighFunction;
import ghidra.program.model.pcode.PcodeOpAST;
import ghidra.program.model.symbol.Reference;
import ghidra.program.model.symbol.Symbol;
public class ShowCCallsScript extends GhidraScript {
private Address lastAddr = null;
@Override
public void run() throws Exception {
if (currentLocation == null) {
println("No Location.");
return;
}
Listing listing = currentProgram.getListing();
Function func = listing.getFunctionContaining(currentAddress);
if (func == null) {
println("No Function at address " + currentAddress);
return;
}
DecompInterface decomplib = setUpDecompiler(currentProgram);
try {
if (!decomplib.openProgram(currentProgram)) {
println("Decompile Error: " + decomplib.getLastMessage());
return;
}
// call decompiler for all refs to current function
Symbol sym = this.getSymbolAt(func.getEntryPoint());
Reference refs[] = sym.getReferences(null);
for (int i = 0; i < refs.length; i++) {
if (monitor.isCancelled()) {
break;
}
// get function containing.
Address refAddr = refs[i].getFromAddress();
Function refFunc = currentProgram.getFunctionManager()
.getFunctionContaining(refAddr);
if (refFunc == null) {
continue;
}
// decompile function
// look for call to this function
// display call
analyzeFunction(decomplib, currentProgram, refFunc, refAddr);
}
}
finally {
decomplib.dispose();
}
lastAddr = null;
}
private DecompInterface setUpDecompiler(Program program) {
DecompInterface decomplib = new DecompInterface();
DecompileOptions options;
options = new DecompileOptions();
OptionsService service = state.getTool().getService(OptionsService.class);
if (service != null) {
ToolOptions opt = service.getOptions("Decompiler");
options.grabFromToolAndProgram(null,opt,program);
}
decomplib.setOptions(options);
decomplib.toggleCCode(true);
decomplib.toggleSyntaxTree(true);
decomplib.setSimplificationStyle("decompile");
return decomplib;
}
/**
* Analyze a functions references
*/
public void analyzeFunction(DecompInterface decomplib, Program prog, Function f, Address refAddr) {
if (f == null) {
return;
}
// don't decompile the function again if it was the same as the last one
//
if (!f.getEntryPoint().equals(lastAddr))
decompileFunction(f, decomplib);
lastAddr = f.getEntryPoint();
Instruction instr = prog.getListing().getInstructionAt(refAddr);
if (instr == null) {
return;
}
println(printCall(f, refAddr));
}
HighFunction hfunction = null;
ClangTokenGroup docroot = null;
public boolean decompileFunction(Function f, DecompInterface decomplib) {
// decomplib.setSimplificationStyle("normalize", null);
// HighFunction hfunction = decomplib.decompileFunction(f);
DecompileResults decompRes = decomplib.decompileFunction(f, decomplib.getOptions().getDefaultTimeout(), monitor);
//String statusMsg = decomplib.getDecompileMessage();
hfunction = decompRes.getHighFunction();
docroot = decompRes.getCCodeMarkup();
if (hfunction == null)
return false;
return true;
}
/**
* get the pcode ops that refer to an address
*/
public Iterator<PcodeOpAST> getPcodeOps(Address refAddr) {
if (hfunction == null) {
return null;
}
Iterator<PcodeOpAST> piter = hfunction.getPcodeOps(refAddr.getPhysicalAddress());
return piter;
}
public String printCall(Function f, Address refAddr) {
StringBuffer buff = new StringBuffer();
printCall(refAddr, docroot, buff, false, false);
return buff.toString();
}
private boolean printCall(Address refAddr, ClangNode node, StringBuffer buff, boolean didStart, boolean isCall) {
if (node == null) {
return false;
}
Address min = node.getMinAddress();
Address max = node.getMaxAddress();
if (min == null)
return false;
if (refAddr.getPhysicalAddress().equals(max) && node instanceof ClangStatement) {
ClangStatement stmt = (ClangStatement) node;
// Don't check for an actual call. The call could be buried more deeply. As long as the original call reference site
// is the max address, then display the results.
// So this block assumes that the last address contained in the call will be the
// address you are looking for.
// - This could lead to strange behavior if the call reference is placed on some address
// that is not the final call point used by the decompiler.
// - Also if there is a delay slot, then the last address for the call reference point
// might not be the last address for the block of PCode.
//if (stmt.getPcodeOp().getOpcode() == PcodeOp.CALL) {
if (!didStart) {
Address nodeAddr = node.getMaxAddress();
// Decompiler only knows base space.
// If reference came from an overlay space, convert address back
if (refAddr.getAddressSpace().isOverlaySpace()) {
nodeAddr = refAddr.getAddressSpace().getOverlayAddress(nodeAddr);
}
buff.append(" " + nodeAddr + " : ");
}
buff.append(" " + toString(stmt));
return true;
//}
}
for (int j = 0; j < node.numChildren(); j++) {
isCall = node instanceof ClangStatement;
didStart |= printCall(refAddr, node.Child(j), buff, didStart, isCall);
}
return didStart;
}
public String toString(ClangStatement node) {
StringBuffer buffer = new StringBuffer();
int open=-1;
for (int j = 0; j < node.numChildren(); j++) {
ClangNode subNode = node.Child(j);
if (subNode instanceof ClangSyntaxToken) {
ClangSyntaxToken syntaxNode = (ClangSyntaxToken) subNode;
if (syntaxNode.getOpen() != -1) {
if (node.Child(j+2) instanceof ClangTypeToken) {
open = syntaxNode.getOpen();
continue;
}
}
if (syntaxNode.getClose() == open && open != -1) {
open = -1;
continue;
}
}
if (open != -1) {
continue;
}
buffer.append(subNode.toString());
}
return buffer.toString();
}
}