mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-10-23 13:41:04 +00:00
GP-1258 SH4 and general reference analysis improvements
This commit is contained in:
parent
eab50936fd
commit
4d44bea5a0
|
@ -40,24 +40,24 @@ import ghidra.program.util.VarnodeContext;
|
|||
|
||||
public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter {
|
||||
protected AddressSet destSet = new AddressSet();
|
||||
private boolean trustMemoryWrite = false;
|
||||
private boolean trustMemoryWrite = false;
|
||||
private long minStoreLoadOffset = 4;
|
||||
private long minSpeculativeOffset = 1024; // from the beginning of memory
|
||||
private long maxSpeculativeOffset = 256; // from the end of memory
|
||||
|
||||
|
||||
public ConstantPropagationContextEvaluator() {
|
||||
public ConstantPropagationContextEvaluator() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param trustMemoryWrite - true to trust values read from memory that is marked writable
|
||||
*/
|
||||
public ConstantPropagationContextEvaluator(boolean trustMemoryWrite) {
|
||||
this.trustMemoryWrite = trustMemoryWrite;
|
||||
/**
|
||||
* @param trustMemoryWrite - true to trust values read from memory that is marked writable
|
||||
*/
|
||||
public ConstantPropagationContextEvaluator(boolean trustMemoryWrite) {
|
||||
this.trustMemoryWrite = trustMemoryWrite;
|
||||
}
|
||||
|
||||
|
||||
public ConstantPropagationContextEvaluator(boolean trustWriteMemOption,
|
||||
long minStoreLoadRefAddress, long minSpeculativeRefAddress, long maxSpeculativeRefAddress) {
|
||||
long minStoreLoadRefAddress, long minSpeculativeRefAddress,
|
||||
long maxSpeculativeRefAddress) {
|
||||
this(trustWriteMemOption);
|
||||
this.minStoreLoadOffset = minStoreLoadRefAddress;
|
||||
this.maxSpeculativeOffset = maxSpeculativeRefAddress;
|
||||
|
@ -68,20 +68,20 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter
|
|||
*
|
||||
* @return a set of destinations that have computed flow where the flow is unknown
|
||||
*/
|
||||
public AddressSet getDestinationSet() {
|
||||
return destSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* If you override this method, and the default behavior of checking 0-256 and mask values is desired,
|
||||
* call super.evaluateConstant() in your overriden method.
|
||||
*/
|
||||
@Override
|
||||
public AddressSet getDestinationSet() {
|
||||
return destSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* If you override this method, and the default behavior of checking 0-256 and mask values is desired,
|
||||
* call super.evaluateConstant() in your overriden method.
|
||||
*/
|
||||
@Override
|
||||
public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop,
|
||||
Address constant, int size, RefType refType) {
|
||||
|
||||
|
||||
// Constant references below minSpeculative or near the end of the address space are suspect,
|
||||
// even if memory exists for those locations.
|
||||
// even if memory exists for those locations.
|
||||
AddressSpace space = constant.getAddressSpace();
|
||||
long maxAddrOffset = space.getMaxAddress().getOffset();
|
||||
long wordOffset = constant.getOffset();
|
||||
|
@ -91,7 +91,7 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter
|
|||
!space.isExternalSpace()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// could just be integer -1 extended into address
|
||||
if (wordOffset == 0xffffffffL || wordOffset == 0xffffL || wordOffset == -1L) {
|
||||
return null;
|
||||
|
@ -100,13 +100,20 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter
|
|||
return constant;
|
||||
}
|
||||
|
||||
/**
|
||||
* If you override this method, and the default behavior of checking 0-256 and mask values is desired,
|
||||
* call super.evaluateReference() in your overriden method.
|
||||
*/
|
||||
/**
|
||||
* If you override this method, and the default behavior of checking 0-256 and mask values is desired,
|
||||
* call super.evaluateReference() in your overriden method.
|
||||
*/
|
||||
@Override
|
||||
public boolean evaluateReference(VarnodeContext context, Instruction instr,
|
||||
int pcodeop, Address address, int size, RefType refType) {
|
||||
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
|
||||
Address address, int size, RefType refType) {
|
||||
|
||||
// special check for parameters, evaluating the call, an uncomputed call wouldn't get here normally
|
||||
// really there should be another callback when adding parameters
|
||||
if (refType.isCall() && !refType.isComputed() && pcodeop == PcodeOp.UNIMPLEMENTED) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// unless this is a direct address copy, don't trust computed accesses below minStoreLoadOffset
|
||||
// External spaces can have low addresses... so don't check them
|
||||
AddressSpace space = address.getAddressSpace();
|
||||
|
@ -128,7 +135,7 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -357,12 +357,13 @@ public class SymbolicPropogator {
|
|||
Address destination;
|
||||
boolean continueAfterHittingFlow;
|
||||
|
||||
public SavedFlowState(Address source, Address destination,
|
||||
public SavedFlowState(VarnodeContext vContext, Address source, Address destination,
|
||||
boolean continueAfterHittingFlow) {
|
||||
super();
|
||||
this.source = source;
|
||||
this.destination = destination;
|
||||
this.continueAfterHittingFlow = continueAfterHittingFlow;
|
||||
vContext.pushMemState();
|
||||
}
|
||||
|
||||
public Address getSource() {
|
||||
|
@ -376,6 +377,10 @@ public class SymbolicPropogator {
|
|||
public boolean isContinueAfterHittingFlow() {
|
||||
return continueAfterHittingFlow;
|
||||
}
|
||||
|
||||
public void restoreState(VarnodeContext vContext) {
|
||||
vContext.popMemState();
|
||||
}
|
||||
}
|
||||
|
||||
// Used to stop runs of the same exact instruction
|
||||
|
@ -401,7 +406,7 @@ public class SymbolicPropogator {
|
|||
|
||||
// prime the context stack with the entry point address
|
||||
Stack<SavedFlowState> contextStack = new Stack<>();
|
||||
contextStack.push(new SavedFlowState(fromAddr, startAddr, true));
|
||||
contextStack.push(new SavedFlowState(vContext, fromAddr, startAddr, true));
|
||||
canceled = false;
|
||||
|
||||
// only stop flowing on unknown bad calls when the stack depth could be unknown
|
||||
|
@ -424,6 +429,7 @@ public class SymbolicPropogator {
|
|||
Address nextAddr = nextFlow.getDestination();
|
||||
Address flowFromAddr = nextFlow.getSource();
|
||||
boolean continueAfterHittingFlow = nextFlow.isContinueAfterHittingFlow();
|
||||
nextFlow.restoreState(vContext);
|
||||
|
||||
// already done it!
|
||||
if (body.contains(nextAddr)) {
|
||||
|
@ -538,8 +544,8 @@ public class SymbolicPropogator {
|
|||
}
|
||||
if (!instrFlow.isCall()) {
|
||||
for (Address flow : flows) {
|
||||
contextStack.push(new SavedFlowState(instr.getMinAddress(), flow,
|
||||
continueAfterHittingFlow));
|
||||
contextStack.push(new SavedFlowState(vContext,
|
||||
instr.getMinAddress(), flow, continueAfterHittingFlow));
|
||||
}
|
||||
}
|
||||
else if (flows.length > 1) {
|
||||
|
@ -548,8 +554,9 @@ public class SymbolicPropogator {
|
|||
for (Reference flowRef : flowRefs) {
|
||||
RefType referenceType = flowRef.getReferenceType();
|
||||
if (referenceType.isComputed() && referenceType.isJump()) {
|
||||
contextStack.push(new SavedFlowState(instr.getMinAddress(),
|
||||
flowRef.getToAddress(), continueAfterHittingFlow));
|
||||
contextStack.push(
|
||||
new SavedFlowState(vContext, instr.getMinAddress(),
|
||||
flowRef.getToAddress(), continueAfterHittingFlow));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -584,7 +591,7 @@ public class SymbolicPropogator {
|
|||
Address fallThru = instr.getFallThrough();
|
||||
nextAddr = null;
|
||||
if (retAddr != null) {
|
||||
contextStack.push(new SavedFlowState(instr.getMinAddress(), retAddr,
|
||||
contextStack.push(new SavedFlowState(vContext, instr.getMinAddress(), retAddr,
|
||||
continueAfterHittingFlow));
|
||||
fallThru = null;
|
||||
}
|
||||
|
@ -592,14 +599,14 @@ public class SymbolicPropogator {
|
|||
if (fallThru != null) {
|
||||
if (doFallThruLast) {
|
||||
// put it lowest on the stack to do later!
|
||||
contextStack.add(0, new SavedFlowState(instr.getMinAddress(), fallThru,
|
||||
!callCouldCauseBadStackDepth));
|
||||
contextStack.push(new SavedFlowState(vContext, instr.getMinAddress(),
|
||||
fallThru, !callCouldCauseBadStackDepth));
|
||||
}
|
||||
else if (fallThru.compareTo(maxAddr) < 0) {
|
||||
// this isn't a normal fallthru, must break it up
|
||||
// don't continue flowing if something else is hit, this is an odd case
|
||||
contextStack.add(0,
|
||||
new SavedFlowState(instr.getMinAddress(), fallThru, false));
|
||||
contextStack.push(
|
||||
new SavedFlowState(vContext, instr.getMinAddress(), fallThru, false));
|
||||
}
|
||||
else {
|
||||
nextAddr = fallThru;
|
||||
|
@ -1763,7 +1770,7 @@ public class SymbolicPropogator {
|
|||
signatureSource = func.getSignatureSource();
|
||||
}
|
||||
|
||||
long callOffset = (callTarget == null ? 0 : callTarget.getOffset());
|
||||
long callOffset = (callTarget == null ? -1 : callTarget.getOffset());
|
||||
|
||||
// If there are params defined or the params were specified (meaning it could be VOID params)
|
||||
boolean signatureAssigned = signatureSource != SourceType.DEFAULT;
|
||||
|
|
|
@ -46,7 +46,7 @@ public class VarnodeContext implements ProcessorContext {
|
|||
protected DisassemblerContextImpl spaceContext;
|
||||
|
||||
// holds temp memory values for computation
|
||||
protected HashMap<Varnode, Varnode> memoryVals = new HashMap<>();
|
||||
protected Stack<HashMap<Varnode, Varnode>> memoryVals = new Stack<HashMap<Varnode, Varnode>>();
|
||||
|
||||
// holds temp values for computation
|
||||
private HashMap<Varnode, Varnode> tempVals = new HashMap<>();
|
||||
|
@ -96,6 +96,8 @@ public class VarnodeContext implements ProcessorContext {
|
|||
offsetContext = new DisassemblerContextImpl(programContext);
|
||||
spaceContext = new DisassemblerContextImpl(spaceProgramContext);
|
||||
|
||||
memoryVals.push(new HashMap<Varnode, Varnode>());
|
||||
|
||||
setupValidSymbolicStackNames(program);
|
||||
|
||||
// get the return value location for functions
|
||||
|
@ -417,7 +419,7 @@ public class VarnodeContext implements ProcessorContext {
|
|||
}
|
||||
|
||||
// see if we wrote a value to memory here
|
||||
Varnode lvalue = memoryVals.get(varnode);
|
||||
Varnode lvalue = getMemoryValue(varnode);
|
||||
if (lvalue != null) {
|
||||
if (debug) {
|
||||
Msg.info(this, " " + varnode + " = " + print(lvalue));
|
||||
|
@ -472,7 +474,6 @@ public class VarnodeContext implements ProcessorContext {
|
|||
|
||||
if (this.program.getListing().getInstructionContaining(addr) != null) {
|
||||
hitDest = true;
|
||||
throw notFoundExc;
|
||||
}
|
||||
|
||||
// don't trust any place that has an external reference off of it
|
||||
|
@ -487,8 +488,8 @@ public class VarnodeContext implements ProcessorContext {
|
|||
// If the memory is Writeable, then maybe don't trust it
|
||||
if (!isReadOnly(addr)) {
|
||||
// don't try to see how far away if it is in a different space.
|
||||
if (addr.getAddressSpace().equals(
|
||||
this.spaceContext.getAddress().getAddressSpace())) {
|
||||
if (addr.getAddressSpace()
|
||||
.equals(this.spaceContext.getAddress().getAddressSpace())) {
|
||||
long diff = addr.subtract(this.spaceContext.getAddress());
|
||||
// if the value loaded is too far away, ask the evaluator if it should be trusted.
|
||||
if (diff < 0 || diff > 4096) {
|
||||
|
@ -546,6 +547,36 @@ public class VarnodeContext implements ProcessorContext {
|
|||
throw notFoundExc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the value state stack for the first occurence of the set value
|
||||
*
|
||||
* @param varnode varnode to search for a value
|
||||
* @return first value found on stack, null otherwise
|
||||
*/
|
||||
protected Varnode getMemoryValue(Varnode varnode) {
|
||||
// traverse pushed memory value states until find value
|
||||
// if don't find, return null
|
||||
for (int i = memoryVals.size() - 1; i >= 0; i--) {
|
||||
HashMap<Varnode, Varnode> stateLayer = memoryVals.get(i);
|
||||
Varnode value = stateLayer.get(varnode);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the value for the varnode on the top of the memory state stack
|
||||
*
|
||||
* @param out varnode for the value
|
||||
* @param value value to store for the varnode
|
||||
*/
|
||||
protected void putMemoryValue(Varnode out, Varnode value) {
|
||||
// put the value in the top memory value states
|
||||
memoryVals.peek().put(out, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the translated stored space value.
|
||||
* SpaceID is stored invert'ed so that the constants for subpieces will blend,
|
||||
|
@ -676,7 +707,7 @@ public class VarnodeContext implements ProcessorContext {
|
|||
// put the location on both the lastSet, and all locations set
|
||||
addSetVarnodeToLastSetLocations(out, location);
|
||||
|
||||
memoryVals.put(out, result);
|
||||
putMemoryValue(out, result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1430,6 +1461,14 @@ public class VarnodeContext implements ProcessorContext {
|
|||
public boolean isSymbolicSpace(int spaceID) {
|
||||
return OffsetAddressFactory.isSymbolSpace(spaceID);
|
||||
}
|
||||
|
||||
public void pushMemState() {
|
||||
memoryVals.push(new HashMap<Varnode, Varnode>());
|
||||
}
|
||||
|
||||
public void popMemState() {
|
||||
memoryVals.pop();
|
||||
}
|
||||
}
|
||||
|
||||
class OffsetAddressFactory extends DefaultAddressFactory {
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
/* ###
|
||||
* 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.
|
||||
*/
|
||||
package ghidra.app.plugin.core.analysis;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.program.disassemble.Disassembler;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
import ghidra.program.model.symbol.RefType;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.util.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class SH4AddressAnalyzer extends ConstantPropagationAnalyzer {
|
||||
|
||||
private static final String OPTION_NAME_PROPAGATE_R12 = "Propagate constant R12";
|
||||
private static final String OPTION_DESCRIPTION_PROPAGATE_R12 =
|
||||
"R12 can be used as a pointer to the GOT table. If it is a constant value propagate the value into called functions.";
|
||||
|
||||
private static final boolean OPTION_DEFAULT_PROPAGATE_R12 = true;
|
||||
|
||||
protected boolean propagateR12 = OPTION_DEFAULT_PROPAGATE_R12;
|
||||
|
||||
protected Register r12;
|
||||
|
||||
private final static String PROCESSOR_NAME = "SuperH4";
|
||||
|
||||
public SH4AddressAnalyzer() {
|
||||
super(PROCESSOR_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAnalyze(Program program) {
|
||||
boolean canAnalyze = program.getLanguage()
|
||||
.getProcessor()
|
||||
.equals(Processor.findOrPossiblyCreateProcessor(PROCESSOR_NAME));
|
||||
|
||||
if (!canAnalyze) {
|
||||
return false;
|
||||
}
|
||||
|
||||
r12 = program.getRegister("r12");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
|
||||
throws CancelledException {
|
||||
return super.added(program, set, monitor, log);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressSetView flowConstants(final Program program, Address flowStart,
|
||||
AddressSetView flowSet, final SymbolicPropogator symEval, final TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
|
||||
final AddressSet coveredSet = new AddressSet();
|
||||
|
||||
// follow all flows building up context
|
||||
// use context to fill out addresses on certain instructions
|
||||
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) {
|
||||
|
||||
@Override
|
||||
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
|
||||
Address address, int size, RefType refType) {
|
||||
|
||||
// if this is a call, some processors use the register value
|
||||
// used in the call for PIC calculations
|
||||
if (refType.isCall()) {
|
||||
// set the called function to have a constant value for this register
|
||||
// WARNING: This might not always be the case, if called directly or with a different register
|
||||
// But then it won't matter, because the function won't depend on the registers value.
|
||||
if (instr.getFlowType().isCall()) {
|
||||
propagateR12ToCall(program, context, address);
|
||||
}
|
||||
}
|
||||
|
||||
boolean doRef =
|
||||
super.evaluateReference(context, instr, pcodeop, address, size, refType);
|
||||
if (!doRef) {
|
||||
return false;
|
||||
}
|
||||
if (checkComputedRelativeBranch(program, monitor, instr, address, refType,
|
||||
pcodeop)) {
|
||||
return false;
|
||||
}
|
||||
return doRef;
|
||||
}
|
||||
};
|
||||
|
||||
AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor);
|
||||
|
||||
// Add in any addresses we should assume got covered
|
||||
// These addresses are put on because we had to stop analysis due to an unknown register value
|
||||
resultSet.add(coveredSet);
|
||||
|
||||
return resultSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is a computed relative branch that needs the reference placed on the correct operand.
|
||||
*
|
||||
* @param program program
|
||||
* @param monitor task monitor
|
||||
* @param instr instruction to add references to
|
||||
* @param address target address
|
||||
* @param refType type of reference
|
||||
* @param pcodeop pcode operation causing the reference
|
||||
* @return true if the reference was handled in this routine
|
||||
*/
|
||||
protected boolean checkComputedRelativeBranch(final Program program, final TaskMonitor monitor,
|
||||
Instruction instr, Address address, RefType refType, int pcodeop) {
|
||||
// unimplemented is a flag for a parameter check
|
||||
if (pcodeop == PcodeOp.UNIMPLEMENTED) {
|
||||
return false;
|
||||
}
|
||||
// non-computed don't need to place the reference
|
||||
if (!refType.isComputed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// force the reference on the first operand for bsrf
|
||||
String mnemonic = instr.getMnemonicString();
|
||||
if (mnemonic.equals("bsrf") || mnemonic.equals("braf")) {
|
||||
instr.addOperandReference(0, address, refType, SourceType.ANALYSIS);
|
||||
|
||||
// need to handle disassembly too
|
||||
Disassembler dis = Disassembler.getDisassembler(program, monitor, null);
|
||||
AddressSet disassembleAddrs = dis.disassemble(address, null);
|
||||
AutoAnalysisManager.getAnalysisManager(program).codeDefined(disassembleAddrs);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void propagateR12ToCall(Program program, VarnodeContext context, Address address) {
|
||||
if (!propagateR12) {
|
||||
return;
|
||||
}
|
||||
|
||||
RegisterValue registerValue = context.getRegisterValue(r12);
|
||||
if (registerValue != null) {
|
||||
BigInteger value = registerValue.getUnsignedValue();
|
||||
ProgramContext progContext = program.getProgramContext();
|
||||
try {
|
||||
progContext.setValue(r12, address, address, value);
|
||||
}
|
||||
catch (ContextChangeException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void optionsChanged(Options options, Program program) {
|
||||
super.optionsChanged(options, program);
|
||||
|
||||
options.registerOption(OPTION_NAME_PROPAGATE_R12, OPTION_DEFAULT_PROPAGATE_R12, null,
|
||||
OPTION_DESCRIPTION_PROPAGATE_R12);
|
||||
|
||||
propagateR12 = options.getBoolean(OPTION_NAME_PROPAGATE_R12, OPTION_DEFAULT_PROPAGATE_R12);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/* ###
|
||||
* 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.
|
||||
*/
|
||||
package ghidra.app.plugin.core.analysis;
|
||||
|
||||
import ghidra.app.services.AnalysisPriority;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Instruction;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.symbol.RefType;
|
||||
import ghidra.program.util.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class SH4EarlyAddressAnalyzer extends SH4AddressAnalyzer {
|
||||
|
||||
/**
|
||||
* The early SH4 address analyzer runs right after disassembly to lay down
|
||||
* any dynamic call or jump references and to install the R12 value which
|
||||
* is use for PIC calculations.
|
||||
* Other calculated references will occur when the functions are better
|
||||
* formed to stop mistakes in functions that flow together incorrectly.
|
||||
*/
|
||||
public SH4EarlyAddressAnalyzer() {
|
||||
super();
|
||||
this.setPriority(AnalysisPriority.DISASSEMBLY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressSetView flowConstants(final Program program, Address flowStart,
|
||||
AddressSetView flowSet, final SymbolicPropogator symEval, final TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
|
||||
final AddressSet coveredSet = new AddressSet();
|
||||
|
||||
// follow all flows building up context
|
||||
// use context to fill out addresses on certain instructions
|
||||
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) {
|
||||
|
||||
@Override
|
||||
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
|
||||
Address address, int size, RefType refType) {
|
||||
|
||||
// if this is a call, some processors use the register value
|
||||
// used in the call for PIC calculations
|
||||
if (refType.isFlow()) {
|
||||
// set the called function to have a constant value for this register
|
||||
// WARNING: This might not always be the case, if called directly or with a different register
|
||||
// But then it won't matter, because the function won't depend on the registers value.
|
||||
if (instr.getFlowType().isCall()) {
|
||||
propagateR12ToCall(program, context, address);
|
||||
}
|
||||
|
||||
if (refType.isComputed()) {
|
||||
boolean doRef = super.evaluateReference(context, instr, pcodeop, address,
|
||||
size, refType);
|
||||
if (!doRef) {
|
||||
return false;
|
||||
}
|
||||
if (checkComputedRelativeBranch(program, monitor, instr, address, refType,
|
||||
pcodeop)) {
|
||||
return false;
|
||||
}
|
||||
return doRef;
|
||||
}
|
||||
}
|
||||
|
||||
// in the Early analyzer, don't lay down anything other than computed call references
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor);
|
||||
|
||||
// Add in any addresses we should assume got covered
|
||||
// These addresses are put on because we had to stop analysis due to an unknown register value
|
||||
resultSet.add(coveredSet);
|
||||
|
||||
return resultSet;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user