mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-26 06:02:29 +00:00
Merge remote-tracking branch 'origin/GP-4364_emteere_SwitchCallotherOptimization--SQUASHED'
This commit is contained in:
commit
9a7ab128df
@ -18,8 +18,6 @@ package ghidra.app.plugin.core.analysis;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import generic.concurrent.*;
|
||||
import ghidra.app.cmd.function.CreateFunctionCmd;
|
||||
import ghidra.app.cmd.function.DecompilerSwitchAnalysisCmd;
|
||||
@ -32,8 +30,11 @@ import ghidra.framework.options.Options;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.block.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.lang.InjectPayload;
|
||||
import ghidra.program.model.lang.PcodeInjectLibrary;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
import ghidra.program.model.pcode.Varnode;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.util.*;
|
||||
import ghidra.util.Msg;
|
||||
@ -53,10 +54,11 @@ public class DecompilerSwitchAnalyzer extends AbstractAnalyzer {
|
||||
public static final int OPTION_DEFAULT_DECOMPILER_TIMEOUT_SECS = 60;
|
||||
private int decompilerTimeoutSecondsOption = OPTION_DEFAULT_DECOMPILER_TIMEOUT_SECS;
|
||||
|
||||
// cache for pcode callother injection payloads
|
||||
private HashMap<Long, InjectPayload> injectPayloadCache = new HashMap<>();
|
||||
|
||||
private boolean hitNonReturningFunction = false;
|
||||
|
||||
private Register isaModeSwitchRegister = null;
|
||||
private Register isaModeRegister = null;
|
||||
|
||||
//==================================================================================================
|
||||
// Interface Methods
|
||||
@ -95,9 +97,6 @@ public class DecompilerSwitchAnalyzer extends AbstractAnalyzer {
|
||||
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
|
||||
throws CancelledException {
|
||||
|
||||
isaModeSwitchRegister = program.getRegister("ISAModeSwitch");
|
||||
isaModeRegister = program.getRegister("ISA_MODE");
|
||||
|
||||
try {
|
||||
ArrayList<Address> locations = findLocations(program, set, monitor);
|
||||
if (locations.isEmpty()) {
|
||||
@ -224,6 +223,16 @@ public class DecompilerSwitchAnalyzer extends AbstractAnalyzer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find locations that could be an unrecovered switches
|
||||
*
|
||||
* @param program program
|
||||
* @param set area of program to check
|
||||
* @param monitor monitor
|
||||
* @return list of addresses that could be a switch
|
||||
*
|
||||
* @throws CancelledException if monitor cancels
|
||||
*/
|
||||
private ArrayList<Address> findLocations(Program program, AddressSetView set,
|
||||
TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
@ -244,6 +253,12 @@ public class DecompilerSwitchAnalyzer extends AbstractAnalyzer {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// check for break type construct
|
||||
if (hasUnrecoverableCallOther(program, instruction)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
Address address = instruction.getMinAddress();
|
||||
locations.add(address);
|
||||
@ -254,6 +269,110 @@ public class DecompilerSwitchAnalyzer extends AbstractAnalyzer {
|
||||
return locations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check an instruction for an unrecoverable computed destination due
|
||||
* to calling a callOther pcode op that has no associated injection.
|
||||
* If there is an associated injection, then it might yet be recoverable.
|
||||
*
|
||||
* @param program program
|
||||
* @param instr branching instruction to check
|
||||
* @return true if there is a callOther that will block switch recovery
|
||||
*/
|
||||
private boolean hasUnrecoverableCallOther(Program program, Instruction instr) {
|
||||
HashSet<Varnode> callOtherOutputs = new HashSet<Varnode>();
|
||||
|
||||
PcodeOp[] pcode = instr.getPcode(true);
|
||||
for (PcodeOp op : pcode) {
|
||||
if (op.getOpcode() == PcodeOp.CALLOTHER) {
|
||||
// if callother has defined pcode inject replacement
|
||||
// then could recover
|
||||
if (hasPcodeInject(program, op)) {
|
||||
continue;
|
||||
}
|
||||
// save callother output varnode
|
||||
Varnode dest = op.getOutput();
|
||||
if (dest != null) {
|
||||
callOtherOutputs.add(dest);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!callOtherOutputs.isEmpty() && op.getOpcode()==PcodeOp.BRANCHIND) {
|
||||
// check if branching to an output varnode of callother
|
||||
if (callOtherOutputs.contains(op.getInput(0))) {
|
||||
// target is computed from a callother output
|
||||
return true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// if have a callother destinations, check for it as an input
|
||||
if (!callOtherOutputs.isEmpty()) {
|
||||
Varnode[] inputs = op.getInputs();
|
||||
for (Varnode in : inputs) {
|
||||
if (callOtherOutputs.contains(in)) {
|
||||
Varnode dest = op.getOutput();
|
||||
if (dest != null) {
|
||||
callOtherOutputs.add(dest);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the callOther Pcode op has an associated injection
|
||||
*
|
||||
* @param program program
|
||||
* @param op callother pcode op
|
||||
* @return true if there is a pcode injection, false otherwise
|
||||
*/
|
||||
private boolean hasPcodeInject(Program program, PcodeOp op) {
|
||||
long callOtherIndex = op.getInput(0).getOffset();
|
||||
InjectPayload payload = findPcodeInjection(program, callOtherIndex);
|
||||
|
||||
return payload != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out if a callother pcode op has a pcodeInjection attached to it
|
||||
*
|
||||
* @param program program
|
||||
* @param callOtherIndex callOther ID index
|
||||
* @return injection payload or null if no register injections
|
||||
*/
|
||||
private InjectPayload findPcodeInjection(Program program, long callOtherIndex) {
|
||||
InjectPayload payload = injectPayloadCache.get(callOtherIndex);
|
||||
|
||||
// has a payload value for the pcode callother index
|
||||
if (payload != null) {
|
||||
return payload;
|
||||
}
|
||||
|
||||
// value null, if contains the key, then already looked up
|
||||
if (injectPayloadCache.containsKey(callOtherIndex)) {
|
||||
return null;
|
||||
}
|
||||
PcodeInjectLibrary snippetLibrary = program.getCompilerSpec().getPcodeInjectLibrary();
|
||||
|
||||
String opName = program.getLanguage().getUserDefinedOpName((int) callOtherIndex);
|
||||
|
||||
// segment is special named injection
|
||||
if ("segment".equals(opName)) {
|
||||
payload =
|
||||
snippetLibrary.getPayload(InjectPayload.EXECUTABLEPCODE_TYPE, "segment_pcode");
|
||||
}
|
||||
else {
|
||||
payload = snippetLibrary.getPayload(InjectPayload.CALLOTHERFIXUP_TYPE, opName);
|
||||
}
|
||||
|
||||
// save payload in cache for next lookup
|
||||
injectPayloadCache.put(callOtherIndex, payload);
|
||||
return payload;
|
||||
}
|
||||
|
||||
private boolean isCallFixup(Program program, Instruction instr, FlowType flowType) {
|
||||
if (!flowType.isCall()) {
|
||||
return false;
|
||||
@ -370,31 +489,9 @@ public class DecompilerSwitchAnalyzer extends AbstractAnalyzer {
|
||||
if (refType.isComputed() && refType.isFlow() &&
|
||||
program.getMemory().contains(address)) {
|
||||
foundCount.incrementAndGet();
|
||||
// don't propagate low code mode, let something else do that
|
||||
// propogateCodeMode(context, address);
|
||||
// don't make references, let other analysis do this
|
||||
//return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void propogateCodeMode(VarnodeContext context, Address addr) {
|
||||
// get CodeModeRegister and flow it to destination, if it is set here
|
||||
|
||||
if (isaModeSwitchRegister == null) {
|
||||
return;
|
||||
}
|
||||
BigInteger value = context.getValue(isaModeSwitchRegister, false);
|
||||
if (value != null && program.getListing().getInstructionAt(addr) == null) {
|
||||
try {
|
||||
program.getProgramContext()
|
||||
.setValue(isaModeRegister, addr, addr, value);
|
||||
}
|
||||
catch (ContextChangeException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}, false, monitor);
|
||||
|
||||
// only found one reference
|
||||
|
Loading…
Reference in New Issue
Block a user