Merge remote-tracking branch 'origin/GP-1258_emteere_SH4andAnalysisImprovements' into patch

This commit is contained in:
ghidra1 2021-09-07 21:50:20 -04:00
commit 415e4ce1ab
6 changed files with 412 additions and 106 deletions

View file

@ -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;
}

View file

@ -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;

View file

@ -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 {

View file

@ -15,60 +15,52 @@
*/
package ghidra.app.plugin.core.analysis;
import ghidra.program.model.listing.ContextChangeException;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Instruction;
import ghidra.program.model.listing.Program;
import ghidra.program.model.listing.ProgramContext;
import java.math.BigInteger;
import ghidra.app.util.importer.MessageLog;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.lang.Processor;
import ghidra.program.model.lang.Register;
import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolUtilities;
import ghidra.program.util.SymbolicPropogator;
import ghidra.program.util.VarnodeContext;
import ghidra.util.task.TaskMonitor;
import ghidra.util.Msg;
import ghidra.util.exception.AssertException;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public class RISCVAddressAnalyzer extends ConstantPropagationAnalyzer {
public static final String RISCV___GLOBAL_POINTER = "__global_pointer$";
private Address gp_assumption_value;
private static final String REGISTER_GP = "gp";
private Register gp;
private static final String PROCESSOR_NAME = "RISCV";
public static final String RISCV___GLOBAL_POINTER = "__global_pointer$";
public RISCVAddressAnalyzer() {
private Address gp_assumption_value;
private static final String REGISTER_GP = "gp";
private Register gp;
private static final String PROCESSOR_NAME = "RISCV";
public RISCVAddressAnalyzer() {
super(PROCESSOR_NAME);
}
@Override
@Override
public boolean canAnalyze(Program program) {
boolean canAnalyze = program.getLanguage().getProcessor().equals(
Processor.findOrPossiblyCreateProcessor(PROCESSOR_NAME));
boolean canAnalyze = program.getLanguage()
.getProcessor()
.equals(Processor.findOrPossiblyCreateProcessor(PROCESSOR_NAME));
if (!canAnalyze) {
return false;
}
gp = program.getRegister(REGISTER_GP);
return true;
}
@Override
}
@Override
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException {
@ -80,16 +72,14 @@ public class RISCVAddressAnalyzer extends ConstantPropagationAnalyzer {
return super.added(program, set, monitor, log);
}
@Override
@Override
public AddressSetView flowConstants(final Program program, Address flowStart,
AddressSetView flowSet, final SymbolicPropogator symEval, final TaskMonitor monitor)
throws CancelledException {
// get the function body
final Function func = program.getFunctionManager().getFunctionContaining(flowStart);
final AddressSet coveredSet = new AddressSet();
// get the function body
final Function func = program.getFunctionManager().getFunctionContaining(flowStart);
if (func != null && gp_assumption_value != null) {
ProgramContext programContext = program.getProgramContext();
@ -97,8 +87,8 @@ public class RISCVAddressAnalyzer extends ConstantPropagationAnalyzer {
if (gpVal == null || !gpVal.hasValue()) {
gpVal = new RegisterValue(gp, BigInteger.valueOf(gp_assumption_value.getOffset()));
try {
program.getProgramContext().setRegisterValue(func.getEntryPoint(),
func.getEntryPoint(), gpVal);
program.getProgramContext()
.setRegisterValue(func.getEntryPoint(), func.getEntryPoint(), gpVal);
}
catch (ContextChangeException e) {
// only happens for context register
@ -106,28 +96,28 @@ public class RISCVAddressAnalyzer extends ConstantPropagationAnalyzer {
}
}
}
// follow all flows building up context
ConstantPropagationContextEvaluator eval =
new ConstantPropagationContextEvaluator(trustWriteMemOption) {
private boolean mustStopNow = false;
@Override
public boolean evaluateContextBefore(VarnodeContext context, Instruction instr) {
return mustStopNow;
}
@Override
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
return mustStopNow;
}
};
new ConstantPropagationContextEvaluator(trustWriteMemOption) {
private boolean mustStopNow = false;
@Override
public boolean evaluateContextBefore(VarnodeContext context, Instruction instr) {
return mustStopNow;
}
@Override
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
return mustStopNow;
}
};
AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor);
resultSet.add(coveredSet);
return resultSet;
}
}
/**
* Check for a global GP register symbol or discovered symbol
* @param program
@ -135,9 +125,8 @@ public class RISCVAddressAnalyzer extends ConstantPropagationAnalyzer {
* @param monitor
*/
private void checkForGlobalGP(Program program, AddressSetView set, TaskMonitor monitor) {
Symbol symbol = SymbolUtilities.getLabelOrFunctionSymbol(program,
RISCV___GLOBAL_POINTER,
err -> Msg.error(this, err));
Symbol symbol = SymbolUtilities.getLabelOrFunctionSymbol(program, RISCV___GLOBAL_POINTER,
err -> Msg.error(this, err));
if (symbol != null) {
gp_assumption_value = symbol.getAddress();
return;

View file

@ -0,0 +1,177 @@
/* ###
* 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 {
// 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);
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);
}
}

View file

@ -0,0 +1,87 @@
/* ###
* 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 {
// 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);
return resultSet;
}
}