mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
GT-2723 Finish configuration for min/max address changes for constant
reference propagation.
This commit is contained in:
parent
3a27a22fed
commit
a57a7a3533
5 changed files with 256 additions and 60 deletions
|
@ -39,37 +39,59 @@
|
||||||
//@category Analysis
|
//@category Analysis
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.app.script.GhidraScript;
|
import ghidra.app.script.GhidraScript;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.address.AddressRange;
|
||||||
|
import ghidra.program.model.address.AddressRangeImpl;
|
||||||
|
import ghidra.program.model.address.AddressRangeIterator;
|
||||||
|
import ghidra.program.model.address.AddressSet;
|
||||||
|
import ghidra.program.model.address.AddressSetView;
|
||||||
|
import ghidra.program.model.address.AddressSpace;
|
||||||
import ghidra.program.model.block.CodeBlock;
|
import ghidra.program.model.block.CodeBlock;
|
||||||
import ghidra.program.model.block.PartitionCodeSubModel;
|
import ghidra.program.model.block.PartitionCodeSubModel;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.OperandType;
|
||||||
|
import ghidra.program.model.lang.Register;
|
||||||
|
import ghidra.program.model.lang.RegisterValue;
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.Function;
|
||||||
import ghidra.program.model.listing.Instruction;
|
import ghidra.program.model.listing.Instruction;
|
||||||
|
import ghidra.program.model.pcode.Varnode;
|
||||||
import ghidra.program.model.symbol.RefType;
|
import ghidra.program.model.symbol.RefType;
|
||||||
|
import ghidra.program.model.symbol.Reference;
|
||||||
import ghidra.program.model.symbol.SourceType;
|
import ghidra.program.model.symbol.SourceType;
|
||||||
import ghidra.program.util.*;
|
import ghidra.program.util.ContextEvaluator;
|
||||||
|
import ghidra.program.util.ContextEvaluatorAdapter;
|
||||||
|
import ghidra.program.util.OperandFieldLocation;
|
||||||
|
import ghidra.program.util.SymbolicPropogator;
|
||||||
|
import ghidra.program.util.VarnodeContext;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
|
||||||
|
|
||||||
public class MultiInstructionMemReference extends GhidraScript {
|
public class MultiInstructionMemReference extends GhidraScript {
|
||||||
|
|
||||||
Address memReferenceLocation = null;
|
Address memReferenceLocation = null;
|
||||||
private Address curInstrloc;
|
private Address curInstrloc;
|
||||||
|
private Object[] inputObjects;
|
||||||
|
private Object[] resultObjects;
|
||||||
|
private Register singleRegister;
|
||||||
|
private boolean registerInOut;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() throws Exception {
|
public void run() throws Exception {
|
||||||
long numInstructions = currentProgram.getListing().getNumInstructions();
|
long numInstructions = currentProgram.getListing().getNumInstructions();
|
||||||
monitor.initialize((int) (numInstructions));
|
monitor.initialize((int) (numInstructions));
|
||||||
monitor.setMessage("Multi-Instruction Reference Markup");
|
monitor.setMessage("Multi-Instruction Reference Markup");
|
||||||
int currentOpIndex = 0;
|
int currentOpIndex = -1;
|
||||||
|
|
||||||
Address start = currentLocation.getAddress();
|
Address start = currentLocation.getAddress();
|
||||||
|
|
||||||
if ((currentSelection == null || currentSelection.isEmpty()) &&
|
if ((currentSelection == null || currentSelection.isEmpty()) &&
|
||||||
currentLocation instanceof OperandFieldLocation) {
|
currentLocation instanceof OperandFieldLocation) {
|
||||||
currentOpIndex = ((OperandFieldLocation) currentLocation).getOperandIndex();
|
OperandFieldLocation operandLocation = (OperandFieldLocation) currentLocation;
|
||||||
|
currentOpIndex = operandLocation.getOperandIndex();
|
||||||
|
int subOpIndex = operandLocation.getSubOperandIndex();
|
||||||
|
singleRegister = getRegister(start, currentOpIndex, subOpIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set up the address set to restrict processing
|
// set up the address set to restrict processing
|
||||||
|
@ -81,6 +103,34 @@ public class MultiInstructionMemReference extends GhidraScript {
|
||||||
findMemRefAtOperand(currentOpIndex, refLocationsSet);
|
findMemRefAtOperand(currentOpIndex, refLocationsSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the register at the location
|
||||||
|
*
|
||||||
|
* @param opIndex index into operands for instruction
|
||||||
|
* @param subOpIndex index into operands for an operand location
|
||||||
|
*
|
||||||
|
* @return register if there is one at the location
|
||||||
|
*/
|
||||||
|
private Register getRegister(Address addr, int opIndex, int subOpIndex) {
|
||||||
|
if (addr == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction instr = currentProgram.getListing().getInstructionContaining(addr);
|
||||||
|
if (instr == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Object> defOpRep = instr.getDefaultOperandRepresentationList(opIndex);
|
||||||
|
if (subOpIndex >= 0 && subOpIndex < defOpRep.size()) {
|
||||||
|
Object obj = defOpRep.get(subOpIndex);
|
||||||
|
if (obj instanceof Register) {
|
||||||
|
return (Register) obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return instr.getRegister(opIndex);
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private boolean isSingleInstructions(AddressSet restrictedSet) {
|
private boolean isSingleInstructions(AddressSet restrictedSet) {
|
||||||
if (restrictedSet.isEmpty()) {
|
if (restrictedSet.isEmpty()) {
|
||||||
|
@ -106,53 +156,154 @@ public class MultiInstructionMemReference extends GhidraScript {
|
||||||
// use context to fill out addresses on certain instructions
|
// use context to fill out addresses on certain instructions
|
||||||
ContextEvaluator eval = new ContextEvaluatorAdapter() {
|
ContextEvaluator eval = new ContextEvaluatorAdapter() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean evaluateContextBefore(VarnodeContext context, Instruction instr) {
|
||||||
|
// if the requested reference was on an input op-object, get context before exec
|
||||||
|
return checkContext(true, opIndex, context, instr);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
|
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
|
||||||
// TODO: could look at instructions like LEA, that are an address to create a reference to something.
|
// if the requested reference was on an output op-object, get context after exec
|
||||||
|
return checkContext(false, opIndex, context, instr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean checkContext(boolean input, final int opIndex, VarnodeContext context, Instruction instr) {
|
||||||
if (instr.getMinAddress().equals(curInstrloc)) {
|
if (instr.getMinAddress().equals(curInstrloc)) {
|
||||||
if (checkInstructionMatch(opIndex, context, instr)) {
|
if (checkInstructionMatch(opIndex, input, context, instr)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// if instruction is in delayslot, assume reference is good.
|
// if instruction is in delayslot, assume reference is good.
|
||||||
if (instr.getDelaySlotDepth() > 0) {
|
if (instr.getDelaySlotDepth() > 0) {
|
||||||
instr = instr.getNext();
|
instr = instr.getNext();
|
||||||
return checkInstructionMatch(opIndex, context, instr);
|
return checkInstructionMatch(opIndex, input, context, instr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private boolean checkInstructionMatch(final int opIdx, VarnodeContext context,
|
@Override
|
||||||
|
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, Address address,
|
||||||
|
int size, RefType refType) {
|
||||||
|
|
||||||
|
return super.evaluateReference(context, instr, pcodeop, address, size, refType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean checkInstructionMatch(final int opIdx, boolean input, VarnodeContext context,
|
||||||
Instruction instr) {
|
Instruction instr) {
|
||||||
int firstIndex = opIdx;
|
List<Object> list = Arrays.asList(input ? inputObjects : resultObjects);
|
||||||
if (instr.getRegister(firstIndex) == null) {
|
|
||||||
firstIndex = 0;
|
for (int index = opIdx; index < instr.getNumOperands(); index++)
|
||||||
}
|
{
|
||||||
for (int index = firstIndex; index < instr.getNumOperands(); index++) {
|
if (getRefsForOperand(context, instr, list, index)) {
|
||||||
Object[] opObjects = instr.getOpObjects(index);
|
// register is both an in/out check if symbolic on out
|
||||||
for (int indexOpObj = 0; indexOpObj < opObjects.length; indexOpObj++) {
|
if (registerInOut) {
|
||||||
if (!(opObjects[indexOpObj] instanceof Register)) {
|
break;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
Register reg = (Register) opObjects[indexOpObj];
|
return true;
|
||||||
RegisterValue rval = context.getRegisterValue(reg);
|
|
||||||
if (rval == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
BigInteger uval = rval.getUnsignedValue();
|
|
||||||
if (uval == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
long offset = uval.longValue();
|
|
||||||
AddressSpace space = instr.getMinAddress().getAddressSpace();
|
|
||||||
Address addr = space.getTruncatedAddress(offset, true);
|
|
||||||
|
|
||||||
// assume that they want the reference, don't worry it isn't in memory
|
|
||||||
makeReference(instr, index, addr, monitor);
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (addSymbolicRefs(input, context, instr, list)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the current operand for references based on input/outputs
|
||||||
|
*
|
||||||
|
* @param context - context holding values
|
||||||
|
* @param instr - instruction under consideration
|
||||||
|
* @param list - input/output lists
|
||||||
|
* @param opIndex - index of operand to check
|
||||||
|
*
|
||||||
|
* @return true if a reference was found
|
||||||
|
*/
|
||||||
|
private boolean getRefsForOperand(VarnodeContext context, Instruction instr, List<Object> list, int opIndex) {
|
||||||
|
Object[] opObjects = instr.getOpObjects(opIndex);
|
||||||
|
for (int indexOpObj = 0; indexOpObj < opObjects.length; indexOpObj++) {
|
||||||
|
if (!(opObjects[indexOpObj] instanceof Register)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Register reg = (Register) opObjects[indexOpObj];
|
||||||
|
|
||||||
|
// if operand has a single register and this isn't it
|
||||||
|
if (singleRegister != null && !reg.equals(singleRegister)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that the register is on the correct input/output list
|
||||||
|
if (!list.contains(reg)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
RegisterValue rval = context.getRegisterValue(reg);
|
||||||
|
if (rval == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BigInteger uval = rval.getUnsignedValue();
|
||||||
|
if (uval == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
long offset = uval.longValue();
|
||||||
|
|
||||||
|
AddressSpace space = instr.getMinAddress().getAddressSpace();
|
||||||
|
Address addr = space.getTruncatedAddress(offset, true);
|
||||||
|
|
||||||
|
// assume that they want the reference, don't worry it isn't in memory
|
||||||
|
makeReference(instr, opIndex, addr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean addSymbolicRefs(boolean input, VarnodeContext context, Instruction instr, List<Object> list) {
|
||||||
|
// get the value of the single register to see if this is the value desired
|
||||||
|
if (singleRegister == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// check that the register is on the correct input/output list
|
||||||
|
if (!list.contains(singleRegister)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Varnode registerVarnodeValue = context.getRegisterVarnodeValue(singleRegister);
|
||||||
|
if (!context.isSymbol(registerVarnodeValue) && !registerVarnodeValue.isRegister()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Address symAddr = registerVarnodeValue.getAddress();
|
||||||
|
if (symAddr == context.BAD_ADDRESS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String valStr = "";
|
||||||
|
if (registerVarnodeValue.isRegister()) {
|
||||||
|
valStr = context.getRegister(registerVarnodeValue).toString();
|
||||||
|
} else {
|
||||||
|
// is an offset from a space
|
||||||
|
String name = symAddr.getAddressSpace().getName();
|
||||||
|
BigInteger offset = symAddr.getOffsetAsBigInteger();
|
||||||
|
valStr = name + " + 0x" + offset.toString(16);
|
||||||
|
}
|
||||||
|
Address lastSetLocation = context.getLastSetLocation(singleRegister, null);
|
||||||
|
|
||||||
|
|
||||||
|
String comment = instr.getComment(Instruction.EOL_COMMENT);
|
||||||
|
if (comment == null) {
|
||||||
|
comment = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
String inoutChar = (input ? " " : "\'");
|
||||||
|
String lastStr = (lastSetLocation != null ? " @" + lastSetLocation : "");
|
||||||
|
|
||||||
|
String markup = singleRegister+inoutChar+"= "+ valStr + lastStr;
|
||||||
|
if (comment.replace('\'',' ').contains(markup.replace('\'',' '))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
comment = (comment.trim().length()==0 ? markup : comment + "\n" + markup);
|
||||||
|
instr.setComment(Instruction.EOL_COMMENT, comment);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,8 +339,14 @@ public class MultiInstructionMemReference extends GhidraScript {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the instruction attempting to markup is in the delayslot, backup an instruction
|
|
||||||
Instruction instr = currentProgram.getListing().getInstructionAt(curInstrloc);
|
Instruction instr = currentProgram.getListing().getInstructionAt(curInstrloc);
|
||||||
|
if (instr != null) {
|
||||||
|
inputObjects = instr.getInputObjects();
|
||||||
|
resultObjects = instr.getResultObjects();
|
||||||
|
registerInOut = checkRegisterInOut(singleRegister, inputObjects, resultObjects);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the instruction attempting to markup is in the delayslot, backup an instruction
|
||||||
if (instr != null && instr.isInDelaySlot()) {
|
if (instr != null && instr.isInDelaySlot()) {
|
||||||
instr = instr.getPrevious();
|
instr = instr.getPrevious();
|
||||||
if (instr != null) {
|
if (instr != null) {
|
||||||
|
@ -209,16 +366,24 @@ public class MultiInstructionMemReference extends GhidraScript {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private boolean checkRegisterInOut(Register reg, Object[] in, Object[] out) {
|
||||||
* @param instruction
|
if (reg == null || in == null || out == null) {
|
||||||
* @param space
|
return false;
|
||||||
* @param scalar
|
}
|
||||||
* @param nextInstr
|
|
||||||
* @param addend
|
List<Object> inList = Arrays.asList(in);
|
||||||
* @param taskMonitor
|
List<Object> outList = Arrays.asList(out);
|
||||||
|
|
||||||
|
return inList.contains(reg) && outList.contains(reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Make the reference on the instruction at the correct location.
|
||||||
|
*
|
||||||
|
* @param instruction to receive reference
|
||||||
|
* @param space reference created in this space
|
||||||
|
* @param scalar used as offset into address space
|
||||||
*/
|
*/
|
||||||
private void makeReference(Instruction instruction, int opIndex, Address addr,
|
private void makeReference(Instruction instruction, int opIndex, Address addr) {
|
||||||
TaskMonitor taskMonitor) {
|
|
||||||
if (instruction.getPrototype().hasDelaySlots()) {
|
if (instruction.getPrototype().hasDelaySlots()) {
|
||||||
instruction = instruction.getNext();
|
instruction = instruction.getNext();
|
||||||
if (instruction == null) {
|
if (instruction == null) {
|
||||||
|
@ -238,6 +403,13 @@ public class MultiInstructionMemReference extends GhidraScript {
|
||||||
if (opIndex == -1) {
|
if (opIndex == -1) {
|
||||||
opIndex = instruction.getNumOperands() - 1;
|
opIndex = instruction.getNumOperands() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if it already has the reference
|
||||||
|
Reference[] referencesFrom = instruction.getReferencesFrom();
|
||||||
|
boolean hasRef = Arrays.stream(referencesFrom).anyMatch(p -> p.getToAddress().equals(addr));
|
||||||
|
if (hasRef) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (opIndex == -1) {
|
if (opIndex == -1) {
|
||||||
instruction.addMnemonicReference(addr, RefType.DATA, SourceType.ANALYSIS);
|
instruction.addMnemonicReference(addr, RefType.DATA, SourceType.ANALYSIS);
|
||||||
|
|
|
@ -67,10 +67,16 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
|
||||||
protected static final int MINKNOWNREFADDRESS_OPTION_DEFAULT_VALUE = 4;
|
protected static final int MINKNOWNREFADDRESS_OPTION_DEFAULT_VALUE = 4;
|
||||||
|
|
||||||
protected static final String MINSPECULATIVEREFADDRESS_OPTION_NAME =
|
protected static final String MINSPECULATIVEREFADDRESS_OPTION_NAME =
|
||||||
"Min speculative reference";
|
"Speculative reference min";
|
||||||
protected static final String MINSPECULATIVEREFADDRESS_OPTION_DESCRIPTION =
|
protected static final String MINSPECULATIVEREFADDRESS_OPTION_DESCRIPTION =
|
||||||
"Minimum speculative reference address for offsets and parameters";
|
"Minimum speculative reference address for offsets and parameters";
|
||||||
protected static final int MINSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE = 1024;
|
protected static final int MINSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE = 1024;
|
||||||
|
|
||||||
|
protected static final String MAXSPECULATIVEREFADDRESS_OPTION_NAME =
|
||||||
|
"Speculative reference max";
|
||||||
|
protected static final String MAXSPECULATIVEREFADDRESS_OPTION_DESCRIPTION =
|
||||||
|
"Maxmimum speculative reference address offset from the end of memory for offsets and parameters";
|
||||||
|
protected static final int MAXSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE = 256;
|
||||||
|
|
||||||
protected final static int NOTIFICATION_INTERVAL = 100;
|
protected final static int NOTIFICATION_INTERVAL = 100;
|
||||||
|
|
||||||
|
@ -80,6 +86,7 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
|
||||||
protected int maxThreadCount = MAXTHREADCOUNT_OPTION_DEFAULT_VALUE;
|
protected int maxThreadCount = MAXTHREADCOUNT_OPTION_DEFAULT_VALUE;
|
||||||
protected long minStoreLoadRefAddress = MINKNOWNREFADDRESS_OPTION_DEFAULT_VALUE;
|
protected long minStoreLoadRefAddress = MINKNOWNREFADDRESS_OPTION_DEFAULT_VALUE;
|
||||||
protected long minSpeculativeRefAddress = MINSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE;
|
protected long minSpeculativeRefAddress = MINSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE;
|
||||||
|
protected long maxSpeculativeRefAddress = MAXSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE;
|
||||||
|
|
||||||
protected boolean followConditional = false;
|
protected boolean followConditional = false;
|
||||||
|
|
||||||
|
@ -391,7 +398,7 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
|
|
||||||
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption,
|
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption,
|
||||||
minStoreLoadRefAddress, minSpeculativeRefAddress);
|
minStoreLoadRefAddress, minSpeculativeRefAddress, maxSpeculativeRefAddress);
|
||||||
|
|
||||||
return symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
|
return symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
|
||||||
}
|
}
|
||||||
|
@ -461,9 +468,13 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
|
||||||
MINKNOWNREFADDRESS_OPTION_DESCRIPTION);
|
MINKNOWNREFADDRESS_OPTION_DESCRIPTION);
|
||||||
|
|
||||||
long size = program.getAddressFactory().getDefaultAddressSpace().getSize();
|
long size = program.getAddressFactory().getDefaultAddressSpace().getSize();
|
||||||
minSpeculativeRefAddress = size * 8;
|
minSpeculativeRefAddress = size * 16;
|
||||||
options.registerOption(MINSPECULATIVEREFADDRESS_OPTION_NAME, minSpeculativeRefAddress, null,
|
options.registerOption(MINSPECULATIVEREFADDRESS_OPTION_NAME, minSpeculativeRefAddress, null,
|
||||||
MINSPECULATIVEREFADDRESS_OPTION_DESCRIPTION);
|
MINSPECULATIVEREFADDRESS_OPTION_DESCRIPTION);
|
||||||
|
|
||||||
|
maxSpeculativeRefAddress = size * 8;
|
||||||
|
options.registerOption(MAXSPECULATIVEREFADDRESS_OPTION_NAME, maxSpeculativeRefAddress, null,
|
||||||
|
MAXSPECULATIVEREFADDRESS_OPTION_DESCRIPTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -479,6 +490,8 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
|
||||||
options.getLong(MINKNOWNREFADDRESS_OPTION_NAME, minStoreLoadRefAddress);
|
options.getLong(MINKNOWNREFADDRESS_OPTION_NAME, minStoreLoadRefAddress);
|
||||||
minSpeculativeRefAddress =
|
minSpeculativeRefAddress =
|
||||||
options.getLong(MINSPECULATIVEREFADDRESS_OPTION_NAME, minSpeculativeRefAddress);
|
options.getLong(MINSPECULATIVEREFADDRESS_OPTION_NAME, minSpeculativeRefAddress);
|
||||||
|
maxSpeculativeRefAddress =
|
||||||
|
options.getLong(MAXSPECULATIVEREFADDRESS_OPTION_NAME, maxSpeculativeRefAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,9 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter
|
||||||
protected AddressSet destSet = new AddressSet();
|
protected AddressSet destSet = new AddressSet();
|
||||||
private boolean trustMemoryWrite = false;
|
private boolean trustMemoryWrite = false;
|
||||||
private long minStoreLoadOffset = 4;
|
private long minStoreLoadOffset = 4;
|
||||||
private long minSpeculativeOffset = 1024;
|
private long minSpeculativeOffset = 1024; // from the beginning of memory
|
||||||
|
private long maxSpeculativeOffset = 256; // from the end of memory
|
||||||
|
|
||||||
|
|
||||||
public ConstantPropagationContextEvaluator() {
|
public ConstantPropagationContextEvaluator() {
|
||||||
}
|
}
|
||||||
|
@ -55,10 +57,10 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConstantPropagationContextEvaluator(boolean trustWriteMemOption,
|
public ConstantPropagationContextEvaluator(boolean trustWriteMemOption,
|
||||||
long minStoreLoadRefAddress, long minSpeculativeRefAddress) {
|
long minStoreLoadRefAddress, long minSpeculativeRefAddress, long maxSpeculativeRefAddress) {
|
||||||
this(trustWriteMemOption);
|
this(trustWriteMemOption);
|
||||||
this.minStoreLoadOffset = minStoreLoadRefAddress;
|
this.minStoreLoadOffset = minStoreLoadRefAddress;
|
||||||
this.minSpeculativeOffset = minSpeculativeRefAddress;
|
this.maxSpeculativeOffset = maxSpeculativeRefAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -85,7 +87,7 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter
|
||||||
long wordOffset = constant.getOffset();
|
long wordOffset = constant.getOffset();
|
||||||
|
|
||||||
if (((wordOffset >= 0 && wordOffset < minSpeculativeOffset) ||
|
if (((wordOffset >= 0 && wordOffset < minSpeculativeOffset) ||
|
||||||
(Math.abs(maxAddrOffset - wordOffset) < minSpeculativeOffset)) &&
|
(Math.abs(maxAddrOffset - wordOffset) < maxSpeculativeOffset)) &&
|
||||||
!space.isExternalSpace()) {
|
!space.isExternalSpace()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ public class SymbolicPropogator {
|
||||||
// 1. How are "register-relative" varnodes distinguished based upon target space ? Not sure how we handle wrapping/truncation concerns.
|
// 1. How are "register-relative" varnodes distinguished based upon target space ? Not sure how we handle wrapping/truncation concerns.
|
||||||
// 1) The offset is the only thing that could be used as a reference.
|
// 1) The offset is the only thing that could be used as a reference.
|
||||||
|
|
||||||
private static final int _POINTER_MIN_BOUNDS = 0x7fff;
|
private static final int _POINTER_MIN_BOUNDS = 0x100;
|
||||||
|
|
||||||
// mask for sub-piece extraction
|
// mask for sub-piece extraction
|
||||||
private static long[] maskSize = { 0xffL, 0xffL, 0xffffL, 0xffffffL, 0xffffffffL, 0xffffffffffL,
|
private static long[] maskSize = { 0xffL, 0xffL, 0xffffL, 0xffffffL, 0xffffffffL, 0xffffffffffL,
|
||||||
|
@ -1836,7 +1836,7 @@ public class SymbolicPropogator {
|
||||||
// see if the offset is a large constant offset from the symbolic space
|
// see if the offset is a large constant offset from the symbolic space
|
||||||
long offset = refLocation.getOffset();
|
long offset = refLocation.getOffset();
|
||||||
|
|
||||||
if (checkPossibleOffsetAddr(offset)) {
|
if (evaluator != null) {
|
||||||
// symbolic spaces will have the name of the symbolic space be the register space
|
// symbolic spaces will have the name of the symbolic space be the register space
|
||||||
// String spaceName = refLocation.getAddress().getAddressSpace().getName();
|
// String spaceName = refLocation.getAddress().getAddressSpace().getName();
|
||||||
// Register register = vContext.getRegister(spaceName);
|
// Register register = vContext.getRegister(spaceName);
|
||||||
|
@ -1850,7 +1850,7 @@ public class SymbolicPropogator {
|
||||||
// }
|
// }
|
||||||
// } else
|
// } else
|
||||||
|
|
||||||
if (evaluator == null) {
|
if (!vContext.isStackSymbolicSpace(refLocation) && evaluator != null) {
|
||||||
Address constant = program.getAddressFactory().getAddress(
|
Address constant = program.getAddressFactory().getAddress(
|
||||||
(int) targetSpaceID.getOffset(), offset);
|
(int) targetSpaceID.getOffset(), offset);
|
||||||
Address newTarget = evaluator.evaluateConstant(vContext, instruction,
|
Address newTarget = evaluator.evaluateConstant(vContext, instruction,
|
||||||
|
@ -2051,7 +2051,7 @@ public class SymbolicPropogator {
|
||||||
*/
|
*/
|
||||||
private int getReferenceSpaceID(Instruction instruction, long offset) {
|
private int getReferenceSpaceID(Instruction instruction, long offset) {
|
||||||
// TODO: this should be passed to the client callback to make the decision
|
// TODO: this should be passed to the client callback to make the decision
|
||||||
if (offset <= 4096 && offset >= -1) {
|
if (offset <= 4 && offset >= -1) {
|
||||||
return -1; // don't make speculative reference to certain offset values
|
return -1; // don't make speculative reference to certain offset values
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -312,7 +312,7 @@ public class VarnodeContext implements ProcessorContext {
|
||||||
/**
|
/**
|
||||||
* Return true if this varnode is stored in the symbolic stack space
|
* Return true if this varnode is stored in the symbolic stack space
|
||||||
*/
|
*/
|
||||||
private boolean isStackSymbolicSpace(Varnode varnode) {
|
public boolean isStackSymbolicSpace(Varnode varnode) {
|
||||||
// symbolic spaces are off of a register, find the space
|
// symbolic spaces are off of a register, find the space
|
||||||
AddressSpace regSpace = addrFactory.getAddressSpace(varnode.getSpace());
|
AddressSpace regSpace = addrFactory.getAddressSpace(varnode.getSpace());
|
||||||
|
|
||||||
|
@ -785,7 +785,9 @@ public class VarnodeContext implements ProcessorContext {
|
||||||
* return the location that this register was last set
|
* return the location that this register was last set
|
||||||
* This is a transient thing, so it should only be used as a particular flow is being processed...
|
* This is a transient thing, so it should only be used as a particular flow is being processed...
|
||||||
*
|
*
|
||||||
* @param reg
|
* @param reg register to find last set location
|
||||||
|
* @param bval value to look for to differentiate set locations, null if don't care
|
||||||
|
*
|
||||||
* @return address that the register was set.
|
* @return address that the register was set.
|
||||||
*/
|
*/
|
||||||
public Address getLastSetLocation(Register reg, BigInteger bval) {
|
public Address getLastSetLocation(Register reg, BigInteger bval) {
|
||||||
|
@ -1256,6 +1258,13 @@ public class VarnodeContext implements ProcessorContext {
|
||||||
// too big anyway,already extended as far as it will go.
|
// too big anyway,already extended as far as it will go.
|
||||||
vnodeVal = createConstantVarnode(vnodeVal.getOffset(), out.getSize());
|
vnodeVal = createConstantVarnode(vnodeVal.getOffset(), out.getSize());
|
||||||
}
|
}
|
||||||
|
} else if (vnodeVal.isRegister() && vnodeVal.getSize() < out.getSize()) {
|
||||||
|
Register reg = getRegister(vnodeVal);
|
||||||
|
if (reg == null) {
|
||||||
|
throw notFoundExc;
|
||||||
|
}
|
||||||
|
int spaceID = getAddressSpace(reg.getName());
|
||||||
|
vnodeVal = createVarnode(0,spaceID,out.getSize());
|
||||||
}
|
}
|
||||||
return vnodeVal;
|
return vnodeVal;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue