mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-4512 Constant propagation and stack analysis performance changes
This commit is contained in:
parent
df505c40a3
commit
c396867209
12 changed files with 1724 additions and 1167 deletions
|
@ -73,13 +73,27 @@ public class CallDepthChangeInfo {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new CallDepthChangeInfo object.
|
* Construct a new CallDepthChangeInfo object.
|
||||||
|
* Using this constructor will NOT track the stack depth at the start/end of each instruction.
|
||||||
|
*
|
||||||
* @param func function to examine
|
* @param func function to examine
|
||||||
*/
|
*/
|
||||||
public CallDepthChangeInfo(Function func) {
|
public CallDepthChangeInfo(Function func) {
|
||||||
|
this(func, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new CallDepthChangeInfo object.
|
||||||
|
* Allows calls to getRegDepth() and getRegValueRepresentation()
|
||||||
|
*
|
||||||
|
* @param func function to examine
|
||||||
|
* @param storeDepthAtEachInstuction true to track stack at start/end of each instruction. allowing
|
||||||
|
* a call to
|
||||||
|
*/
|
||||||
|
public CallDepthChangeInfo(Function func, boolean storeDepthAtEachInstuction) {
|
||||||
this.program = func.getProgram();
|
this.program = func.getProgram();
|
||||||
frameReg = program.getCompilerSpec().getStackPointer();
|
frameReg = program.getCompilerSpec().getStackPointer();
|
||||||
try {
|
try {
|
||||||
initialize(func, func.getBody(), frameReg, TaskMonitor.DUMMY);
|
initialize(func, func.getBody(), frameReg, storeDepthAtEachInstuction, TaskMonitor.DUMMY);
|
||||||
}
|
}
|
||||||
catch (CancelledException e) {
|
catch (CancelledException e) {
|
||||||
throw new RuntimeException("Unexpected Exception", e);
|
throw new RuntimeException("Unexpected Exception", e);
|
||||||
|
@ -88,10 +102,8 @@ public class CallDepthChangeInfo {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new CallDepthChangeInfo object.
|
* Construct a new CallDepthChangeInfo object.
|
||||||
* @param func
|
* @param func function to examine
|
||||||
* function to examine
|
* @param monitor used to cancel the operation
|
||||||
* @param monitor
|
|
||||||
* monitor used to cancel the operation
|
|
||||||
*
|
*
|
||||||
* @throws CancelledException
|
* @throws CancelledException
|
||||||
* if the operation was canceled
|
* if the operation was canceled
|
||||||
|
@ -102,6 +114,8 @@ public class CallDepthChangeInfo {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new CallDepthChangeInfo object.
|
* Construct a new CallDepthChangeInfo object.
|
||||||
|
* Using this constructor will track the stack depth at the start/end of each instruction.
|
||||||
|
*
|
||||||
* @param function function to examine
|
* @param function function to examine
|
||||||
* @param restrictSet set of addresses to restrict flow flowing to.
|
* @param restrictSet set of addresses to restrict flow flowing to.
|
||||||
* @param frameReg register that is to have it's depth(value) change tracked
|
* @param frameReg register that is to have it's depth(value) change tracked
|
||||||
|
@ -116,34 +130,18 @@ public class CallDepthChangeInfo {
|
||||||
if (frameReg == null) {
|
if (frameReg == null) {
|
||||||
frameReg = program.getCompilerSpec().getStackPointer();
|
frameReg = program.getCompilerSpec().getStackPointer();
|
||||||
}
|
}
|
||||||
initialize(function, restrictSet, frameReg, monitor);
|
// track start/end values at each instruction
|
||||||
|
initialize(function, restrictSet, frameReg, true, monitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a new CallDepthChangeInfo object.
|
|
||||||
*
|
|
||||||
* @param program program containing the function to examime
|
|
||||||
* @param addr address within the function to examine
|
|
||||||
* @param restrictSet set of addresses to restrict flow flowing to.
|
|
||||||
* @param frameReg register that is to have it's depth(value) change tracked
|
|
||||||
* @param monitor monitor used to cancel the operation
|
|
||||||
* @throws CancelledException
|
|
||||||
* if the operation was canceled
|
|
||||||
*/
|
|
||||||
public CallDepthChangeInfo(Program program, Address addr, AddressSetView restrictSet,
|
|
||||||
Register frameReg, TaskMonitor monitor) throws CancelledException {
|
|
||||||
Function func = program.getFunctionManager().getFunctionContaining(addr);
|
|
||||||
Register stackPtrReg = program.getCompilerSpec().getStackPointer();
|
|
||||||
initialize(func, restrictSet, stackPtrReg, monitor);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initialize(Function func, AddressSetView restrictSet, Register reg,
|
private void initialize(Function func, AddressSetView restrictSet, Register reg,
|
||||||
TaskMonitor monitor) throws CancelledException {
|
boolean storeDepthAtEachInstuction, TaskMonitor monitor) throws CancelledException {
|
||||||
changeMap = new DefaultIntPropertyMap("change");
|
changeMap = new DefaultIntPropertyMap("change");
|
||||||
depthMap = new DefaultIntPropertyMap("depth");
|
depthMap = new DefaultIntPropertyMap("depth");
|
||||||
trans = new VarnodeTranslator(program);
|
trans = new VarnodeTranslator(program);
|
||||||
|
|
||||||
symEval = new SymbolicPropogator(program);
|
symEval = new SymbolicPropogator(program,storeDepthAtEachInstuction);
|
||||||
symEval.setParamRefCheck(false);
|
symEval.setParamRefCheck(false);
|
||||||
symEval.setReturnRefCheck(false);
|
symEval.setReturnRefCheck(false);
|
||||||
symEval.setStoredRefCheck(false);
|
symEval.setStoredRefCheck(false);
|
||||||
|
@ -494,18 +492,14 @@ public class CallDepthChangeInfo {
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateContextBefore(VarnodeContext context, Instruction instr) {
|
public boolean evaluateContextBefore(VarnodeContext context, Instruction instr) {
|
||||||
Varnode stackRegVarnode = context.getRegisterVarnode(frameReg);
|
Varnode stackRegVarnode = context.getRegisterVarnode(frameReg);
|
||||||
Varnode stackValue = null;
|
Varnode stackValue = context.getValue(stackRegVarnode, true, this);
|
||||||
try {
|
|
||||||
stackValue = context.getValue(stackRegVarnode, true, this);
|
|
||||||
|
|
||||||
if (stackValue != null && context.isSymbol(stackValue) &&
|
if (stackValue != null && context.isSymbol(stackValue) &&
|
||||||
context.isStackSymbolicSpace(stackValue)) {
|
context.isStackSymbolicSpace(stackValue)) {
|
||||||
int stackPointerDepth = (int) stackValue.getOffset();
|
long stackPointerDepth = stackValue.getOffset();
|
||||||
setDepth(instr, stackPointerDepth);
|
int size = stackValue.getSize();
|
||||||
}
|
stackPointerDepth = (stackPointerDepth << 8 * (8 - size)) >> 8 * (8 - size);
|
||||||
}
|
setDepth(instr, (int) stackPointerDepth);
|
||||||
catch (NotFoundException e) {
|
|
||||||
// ignore
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -621,25 +615,14 @@ public class CallDepthChangeInfo {
|
||||||
return getRegDepth(addr, stackReg);
|
return getRegDepth(addr, stackReg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Get the stack register depth at address.
|
||||||
|
* To have a valid value, the class must be constructed to storeDepthAtEachInstuction
|
||||||
|
*
|
||||||
* @param addr the address to get the register depth at.
|
* @param addr the address to get the register depth at.
|
||||||
* @param reg the register to get the depth of.
|
* @param reg the register to get the depth of.
|
||||||
* @return the depth of the register at the address.
|
* @return the depth of the register at the address.
|
||||||
*/
|
*/
|
||||||
public int getRegDepth(Address addr, Register reg) {
|
public int getRegDepth(Address addr, Register reg) {
|
||||||
// OK lets CHEAT...
|
|
||||||
// Since single instructions will give the wrong value,
|
|
||||||
// get the value as of the end of the last instruction that fell into this one!
|
|
||||||
Instruction instr = this.program.getListing().getInstructionAt(addr);
|
|
||||||
if (instr != null && instr.getLength() < 2) {
|
|
||||||
Address fallAddr = instr.getFallFrom();
|
|
||||||
if (fallAddr != null) {
|
|
||||||
addr = fallAddr;
|
|
||||||
}
|
|
||||||
// just in case this instruction falling from is bigger than 1 byte
|
|
||||||
instr = program.getListing().getInstructionAt(addr);
|
|
||||||
addr = instr.getMaxAddress();
|
|
||||||
}
|
|
||||||
Value rValue = symEval.getRegisterValue(addr, reg);
|
Value rValue = symEval.getRegisterValue(addr, reg);
|
||||||
if (rValue == null) {
|
if (rValue == null) {
|
||||||
return Function.INVALID_STACK_DEPTH_CHANGE;
|
return Function.INVALID_STACK_DEPTH_CHANGE;
|
||||||
|
@ -657,6 +640,11 @@ public class CallDepthChangeInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Get the stack register value as a printable string. This can be an equation
|
||||||
|
* of register+value.
|
||||||
|
*
|
||||||
|
* To have a valid value, the class must be constructed to storeDepthAtEachInstuction
|
||||||
|
*
|
||||||
* @param addr the address of the register value to get the representation of.
|
* @param addr the address of the register value to get the representation of.
|
||||||
* @param reg the register to get the representation of.
|
* @param reg the register to get the representation of.
|
||||||
* @return the string representation of the register value.
|
* @return the string representation of the register value.
|
||||||
|
|
|
@ -43,6 +43,8 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
|
||||||
private static final int MAX_PARAM_OFFSET = 2048; // max size of param reference space
|
private static final int MAX_PARAM_OFFSET = 2048; // max size of param reference space
|
||||||
private static final int MAX_LOCAL_OFFSET = -(64 * 1024); // max size of local reference space
|
private static final int MAX_LOCAL_OFFSET = -(64 * 1024); // max size of local reference space
|
||||||
|
|
||||||
|
private final static String X86_NAME = "x86";
|
||||||
|
|
||||||
private boolean dontCreateNewVariables = false;
|
private boolean dontCreateNewVariables = false;
|
||||||
|
|
||||||
private final boolean forceProcessing;
|
private final boolean forceProcessing;
|
||||||
|
@ -54,6 +56,8 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
|
||||||
private Register stackReg;
|
private Register stackReg;
|
||||||
private int purge = 0;
|
private int purge = 0;
|
||||||
|
|
||||||
|
private boolean isX86 = false;
|
||||||
|
|
||||||
static String DEFAULT_FUNCTION_COMMENT = " FUNCTION";
|
static String DEFAULT_FUNCTION_COMMENT = " FUNCTION";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -102,6 +106,8 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
|
||||||
public boolean applyTo(Program p, TaskMonitor monitor) {
|
public boolean applyTo(Program p, TaskMonitor monitor) {
|
||||||
program = p;
|
program = p;
|
||||||
|
|
||||||
|
isX86 = checkForX86(p);
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
long numAddresses = entryPoints.getNumAddresses();
|
long numAddresses = entryPoints.getNumAddresses();
|
||||||
int numRanges = entryPoints.getNumAddressRanges();
|
int numRanges = entryPoints.getNumAddressRanges();
|
||||||
|
@ -138,6 +144,11 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean checkForX86(Program p) {
|
||||||
|
return program.getLanguage().getProcessor().equals(
|
||||||
|
Processor.findOrPossiblyCreateProcessor(X86_NAME)) && program.getDefaultPointerSize() <= 32;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyze a function to build a stack frame based on stack references.
|
* Analyze a function to build a stack frame based on stack references.
|
||||||
*
|
*
|
||||||
|
@ -245,7 +256,7 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
|
||||||
*
|
*
|
||||||
* @param func - function to analyze stack pointer references
|
* @param func - function to analyze stack pointer references
|
||||||
*/
|
*/
|
||||||
private int createStackPointerVariables(Function func, TaskMonitor monitor)
|
private int createStackPointerVariables(final Function func, TaskMonitor monitor)
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
// check if this is a jump thunk through a function pointer
|
// check if this is a jump thunk through a function pointer
|
||||||
// if (checkThunk(func, monitor)) {
|
// if (checkThunk(func, monitor)) {
|
||||||
|
@ -271,7 +282,7 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
|
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
|
||||||
if (instr.getFlowType().isTerminal()) {
|
if (instr.getFlowType().isTerminal()) {
|
||||||
RegisterValue value = context.getRegisterValue(stackReg, instr.getMaxAddress());
|
RegisterValue value = context.getRegisterValue(stackReg);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
BigInteger signedValue = value.getSignedValue();
|
BigInteger signedValue = value.getSignedValue();
|
||||||
if (signedValue != null) {
|
if (signedValue != null) {
|
||||||
|
@ -279,7 +290,7 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (instr.getMnemonicString().equals("LEA")) {
|
if (isX86 && instr.getMnemonicString().equals("LEA")) {
|
||||||
Register destReg = instr.getRegister(0);
|
Register destReg = instr.getRegister(0);
|
||||||
if (destReg != null) {
|
if (destReg != null) {
|
||||||
Varnode value = context.getRegisterVarnodeValue(destReg);
|
Varnode value = context.getRegisterVarnodeValue(destReg);
|
||||||
|
@ -320,18 +331,17 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
|
||||||
if (opIndex == -1) {
|
if (opIndex == -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// if restoring the same value into the register, don't record the reference
|
||||||
// TODO: Dirty Dirty nasty Hack for POP EBP problem, only very few cases of this!
|
// TODO: Dirty Dirty nasty Hack for POP EBP problem, only very few cases of this!
|
||||||
if (instr.getMnemonicString().equals("POP")) {
|
if (isX86 && instr.getMnemonicString().equals("POP")) {
|
||||||
Register reg = instr.getRegister(opIndex);
|
Register reg = instr.getRegister(opIndex);
|
||||||
if (reg != null && reg.getName().contains("BP")) {
|
if (reg != null && reg.getName().contains("BP")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
long extendedOffset =
|
long extendedOffset = extendOffset(address.getOffset(), stackReg.getBitLength());
|
||||||
extendOffset(address.getOffset(), stackReg.getBitLength());
|
|
||||||
Function func =
|
defineFuncVariable(symEval, func, instr, opIndex, (int) extendedOffset, sortedVariables);
|
||||||
program.getFunctionManager().getFunctionContaining(instr.getMinAddress());
|
|
||||||
defineFuncVariable(func, instr, opIndex, (int) extendedOffset, sortedVariables);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,9 +352,10 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// set the stack pointer to be tracked
|
// set the stack pointer to be tracked
|
||||||
symEval.setRegister(func.getEntryPoint(), stackReg);
|
Address entryPoint = func.getEntryPoint();
|
||||||
|
symEval.setRegister(entryPoint, stackReg);
|
||||||
|
|
||||||
symEval.flowConstants(func.getEntryPoint(), func.getBody(), eval, true, monitor);
|
symEval.flowConstants(entryPoint, func.getBody(), eval, true, monitor);
|
||||||
|
|
||||||
if (sortedVariables.size() != 0) {
|
if (sortedVariables.size() != 0) {
|
||||||
|
|
||||||
|
@ -623,11 +634,11 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
|
||||||
// return true;
|
// return true;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
private void defineFuncVariable(Function func, Instruction instr, int opIndex, int stackOffset,
|
private void defineFuncVariable(SymbolicPropogator symEval, Function func, Instruction instr, int opIndex, int stackOffset,
|
||||||
List<Variable> sortedVariables) {
|
List<Variable> sortedVariables) {
|
||||||
|
|
||||||
ReferenceManager refMgr = program.getReferenceManager();
|
ReferenceManager refMgr = program.getReferenceManager();
|
||||||
int refSize = getRefSize(instr, opIndex);
|
int refSize = getRefSize(symEval, instr, opIndex);
|
||||||
try {
|
try {
|
||||||
// don't create crazy offsets
|
// don't create crazy offsets
|
||||||
if (stackOffset > MAX_PARAM_OFFSET || stackOffset < MAX_LOCAL_OFFSET) {
|
if (stackOffset > MAX_PARAM_OFFSET || stackOffset < MAX_LOCAL_OFFSET) {
|
||||||
|
@ -660,15 +671,16 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Look at the result register to try and figure out stack access size.
|
* Look at the result register to try and figure out stack access size.
|
||||||
|
* @param symEval
|
||||||
*
|
*
|
||||||
* @param instr instruction being analyzed
|
* @param instr instruction being analyzed
|
||||||
* @param opIndex operand that has a stack reference.
|
* @param opIndex operand that has a stack reference.
|
||||||
*
|
*
|
||||||
* @return size of value referenced on the stack
|
* @return size of value referenced on the stack
|
||||||
*/
|
*/
|
||||||
private int getRefSize(Instruction instr, int opIndex) {
|
private int getRefSize(SymbolicPropogator symEval, Instruction instr, int opIndex) {
|
||||||
if (instr.getProgram().getLanguage().supportsPcode()) {
|
if (instr.getProgram().getLanguage().supportsPcode()) {
|
||||||
PcodeOp[] pcode = instr.getPcode();
|
PcodeOp[] pcode = symEval.getInstructionPcode(instr);
|
||||||
for (int i = pcode.length - 1; i >= 0; i--) {
|
for (int i = pcode.length - 1; i >= 0; i--) {
|
||||||
if (pcode[i].getOpcode() == PcodeOp.LOAD) {
|
if (pcode[i].getOpcode() == PcodeOp.LOAD) {
|
||||||
Varnode out = pcode[i].getOutput();
|
Varnode out = pcode[i].getOutput();
|
||||||
|
@ -810,7 +822,7 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
|
||||||
offset = minOffset;
|
offset = minOffset;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dt = Undefined.getUndefinedDataType(size);
|
dt = Undefined.getUndefinedDataType(refSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
Variable var;
|
Variable var;
|
||||||
|
|
|
@ -108,7 +108,6 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
|
||||||
|
|
||||||
final static HashSet<String> handledProcessors = new HashSet<String>();
|
final static HashSet<String> handledProcessors = new HashSet<String>();
|
||||||
protected String processorName = "Basic";
|
protected String processorName = "Basic";
|
||||||
protected AddressSetView EMPTY_ADDRESS_SET = new AddressSet();
|
|
||||||
|
|
||||||
public ConstantPropagationAnalyzer() {
|
public ConstantPropagationAnalyzer() {
|
||||||
this("Basic");
|
this("Basic");
|
||||||
|
@ -189,7 +188,8 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
|
||||||
int locationCount = locations.size();
|
int locationCount = locations.size();
|
||||||
monitor.initialize(locationCount);
|
monitor.initialize(locationCount);
|
||||||
if (locationCount != 0) {
|
if (locationCount != 0) {
|
||||||
AddressSetView resultSet = runAddressAnalysis(program, locations, monitor);
|
monitor.setMessage(getName());
|
||||||
|
AddressSetView resultSet = runParallelAddressAnalysis(program, locations, null, maxThreadCount, monitor);
|
||||||
// get rid of any reached addresses
|
// get rid of any reached addresses
|
||||||
unanalyzedSet.delete(resultSet);
|
unanalyzedSet.delete(resultSet);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,21 +15,32 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.function;
|
package ghidra.app.plugin.core.function;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
import ghidra.app.cmd.function.FunctionStackAnalysisCmd;
|
import ghidra.app.cmd.function.FunctionStackAnalysisCmd;
|
||||||
import ghidra.app.cmd.function.NewFunctionStackAnalysisCmd;
|
import ghidra.app.cmd.function.NewFunctionStackAnalysisCmd;
|
||||||
import ghidra.app.services.*;
|
import ghidra.app.services.*;
|
||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.framework.cmd.BackgroundCommand;
|
import ghidra.framework.cmd.BackgroundCommand;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.program.model.address.AddressSetView;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
|
import ghidra.program.model.listing.Function;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public class StackVariableAnalyzer extends AbstractAnalyzer {
|
public class StackVariableAnalyzer extends AbstractAnalyzer {
|
||||||
private static final String NAME = "Stack";
|
private static final String NAME = "Stack";
|
||||||
private static final String DESCRIPTION = "Creates stack variables for a function.";
|
private static final String DESCRIPTION = "Creates stack variables for a function.";
|
||||||
|
|
||||||
|
protected static final String MAX_THREAD_COUNT_OPTION_NAME = "Max Threads";
|
||||||
|
protected static final String MAX_THREAD_COUNT_OPTION_DESCRIPTION =
|
||||||
|
"Maximum threads for stack variable reference creation. Too many threads causes thrashing in DB.";
|
||||||
|
protected static final int MAX_THREAD_COUNT_OPTION_DEFAULT_VALUE = 2;
|
||||||
|
|
||||||
|
protected int maxThreadCount = MAX_THREAD_COUNT_OPTION_DEFAULT_VALUE;
|
||||||
private boolean doNewStackAnalysis = true;
|
private boolean doNewStackAnalysis = true;
|
||||||
private boolean doCreateLocalStackVars = true;
|
private boolean doCreateLocalStackVars = true;
|
||||||
private boolean doCreateStackParams = false;
|
private boolean doCreateStackParams = false;
|
||||||
|
@ -42,37 +53,88 @@ public class StackVariableAnalyzer extends AbstractAnalyzer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) {
|
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) throws CancelledException {
|
||||||
BackgroundCommand<Program> cmd;
|
BackgroundCommand<Program> cmd;
|
||||||
|
|
||||||
if (doNewStackAnalysis) {
|
// first split out all the function locations, make those the starts
|
||||||
cmd = new NewFunctionStackAnalysisCmd(set, doCreateStackParams, doCreateLocalStackVars,
|
// remove those from the bodies from the given set of addresses
|
||||||
false);
|
Set<Address> locations = new HashSet<Address>();
|
||||||
|
findDefinedFunctions(program, set, locations, monitor);
|
||||||
|
|
||||||
|
int locationCount = locations.size();
|
||||||
|
monitor.initialize(locationCount);
|
||||||
|
try {
|
||||||
|
monitor.setMessage(getName());
|
||||||
|
AddressSetView resultSet = runParallelAddressAnalysis(program, locations, null, maxThreadCount, monitor);
|
||||||
}
|
}
|
||||||
else {
|
catch (Exception e) {
|
||||||
cmd = new FunctionStackAnalysisCmd(set, doCreateStackParams, doCreateLocalStackVars,
|
Msg.error(this, "caught exception", e);
|
||||||
false);
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.applyTo(program, monitor);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean useOldStackAnalysisByDefault(Program program) {
|
@Override
|
||||||
Language language = program.getLanguage();
|
public AddressSetView analyzeLocation(final Program program, Address start, AddressSetView set,
|
||||||
if (language.getProcessor().equals(Processor.findOrPossiblyCreateProcessor("x86"))) {
|
final TaskMonitor monitor) throws CancelledException {
|
||||||
if (language.getLanguageDescription().getSize() == 16) {
|
BackgroundCommand<Program> cmd;
|
||||||
// Prefer using old stack analysis for x86 16-bit with segmented addresses
|
|
||||||
return true;
|
if (doNewStackAnalysis) {
|
||||||
}
|
cmd = new NewFunctionStackAnalysisCmd(new AddressSet(start, start), doCreateStackParams, doCreateLocalStackVars,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
return false;
|
else {
|
||||||
|
cmd = new FunctionStackAnalysisCmd(new AddressSet(start, start), doCreateStackParams, doCreateLocalStackVars,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
cmd.applyTo(program, monitor);
|
||||||
|
|
||||||
|
return EMPTY_ADDRESS_SET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find function locations and adding the function entry points to locations
|
||||||
|
*
|
||||||
|
* @param program program
|
||||||
|
* @param set remove known function bodies from the set, leave entry points
|
||||||
|
* @param locations set of known function start addresses
|
||||||
|
* @param monitor to cancel
|
||||||
|
* @throws CancelledException if cancelled
|
||||||
|
*/
|
||||||
|
protected void findDefinedFunctions(Program program, AddressSetView set,
|
||||||
|
Set<Address> locations, TaskMonitor monitor) throws CancelledException {
|
||||||
|
|
||||||
|
monitor.setMessage("Finding function locations...");
|
||||||
|
long total = set.getNumAddresses();
|
||||||
|
monitor.initialize(total);
|
||||||
|
|
||||||
|
// iterate over functions in program
|
||||||
|
// add each defined function start to the list
|
||||||
|
// return the address set that is minus the bodies of each function
|
||||||
|
Iterator<Function> fiter = program.getFunctionManager().getFunctionsOverlapping(set);
|
||||||
|
while (fiter.hasNext()) {
|
||||||
|
monitor.checkCancelled();
|
||||||
|
Function function = fiter.next();
|
||||||
|
locations.add(function.getEntryPoint());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// private boolean useOldStackAnalysisByDefault(Program program) {
|
||||||
|
// Language language = program.getLanguage();
|
||||||
|
// if (language.getProcessor().equals(Processor.findOrPossiblyCreateProcessor("x86"))) {
|
||||||
|
// if (language.getLanguageDescription().getSize() == 16) {
|
||||||
|
// // Prefer using old stack analysis for x86 16-bit with segmented addresses
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerOptions(Options options, Program program) {
|
public void registerOptions(Options options, Program program) {
|
||||||
options.registerOption(GhidraLanguagePropertyKeys.USE_NEW_FUNCTION_STACK_ANALYSIS,
|
options.registerOption(GhidraLanguagePropertyKeys.USE_NEW_FUNCTION_STACK_ANALYSIS,
|
||||||
!useOldStackAnalysisByDefault(program), null,
|
true, null,
|
||||||
"Use General Stack Reference Propogator (This works best on most processors)");
|
"Use General Stack Reference Propogator (This works best on most processors)");
|
||||||
|
|
||||||
options.registerOption("Create Local Variables", doCreateLocalStackVars, null,
|
options.registerOption("Create Local Variables", doCreateLocalStackVars, null,
|
||||||
|
@ -80,18 +142,23 @@ public class StackVariableAnalyzer extends AbstractAnalyzer {
|
||||||
|
|
||||||
options.registerOption("Create Param Variables", doCreateStackParams, null,
|
options.registerOption("Create Param Variables", doCreateStackParams, null,
|
||||||
"Create Function Parameter stack variables and references");
|
"Create Function Parameter stack variables and references");
|
||||||
|
|
||||||
|
options.registerOption(MAX_THREAD_COUNT_OPTION_NAME, maxThreadCount, null,
|
||||||
|
MAX_THREAD_COUNT_OPTION_DESCRIPTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void optionsChanged(Options options, Program program) {
|
public void optionsChanged(Options options, Program program) {
|
||||||
doNewStackAnalysis =
|
doNewStackAnalysis =
|
||||||
options.getBoolean(GhidraLanguagePropertyKeys.USE_NEW_FUNCTION_STACK_ANALYSIS,
|
options.getBoolean(GhidraLanguagePropertyKeys.USE_NEW_FUNCTION_STACK_ANALYSIS,
|
||||||
!useOldStackAnalysisByDefault(program));
|
true);
|
||||||
|
|
||||||
doCreateLocalStackVars =
|
doCreateLocalStackVars =
|
||||||
options.getBoolean("Create Local Variables", doCreateLocalStackVars);
|
options.getBoolean("Create Local Variables", doCreateLocalStackVars);
|
||||||
|
|
||||||
doCreateStackParams = options.getBoolean("Create Param Variables", doCreateStackParams);
|
doCreateStackParams = options.getBoolean("Create Param Variables", doCreateStackParams);
|
||||||
|
|
||||||
|
maxThreadCount = options.getInt(MAX_THREAD_COUNT_OPTION_NAME, maxThreadCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,13 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.services;
|
package ghidra.app.services;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import generic.concurrent.*;
|
||||||
|
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
|
||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.program.model.address.AddressSetView;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
@ -31,6 +35,8 @@ public abstract class AbstractAnalyzer implements Analyzer {
|
||||||
private boolean isPrototype = false;
|
private boolean isPrototype = false;
|
||||||
private AnalysisPriority priority = AnalysisPriority.LOW_PRIORITY;
|
private AnalysisPriority priority = AnalysisPriority.LOW_PRIORITY;
|
||||||
|
|
||||||
|
protected static final AddressSetView EMPTY_ADDRESS_SET = new AddressSetViewAdapter();
|
||||||
|
|
||||||
protected AbstractAnalyzer(String name, String description, AnalyzerType type) {
|
protected AbstractAnalyzer(String name, String description, AnalyzerType type) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
@ -118,4 +124,95 @@ public abstract class AbstractAnalyzer implements Analyzer {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analyze a single location
|
||||||
|
*
|
||||||
|
* @param program - program to analyze
|
||||||
|
* @param start - location to start flowing constants
|
||||||
|
* @param set - restriction set of addresses to analyze
|
||||||
|
* @param monitor - monitor to check canceled
|
||||||
|
*
|
||||||
|
* @return - set of addresses actually flowed to
|
||||||
|
* @throws CancelledException
|
||||||
|
*/
|
||||||
|
public AddressSetView analyzeLocation(final Program program, Address start, AddressSetView set,
|
||||||
|
final TaskMonitor monitor) throws CancelledException {
|
||||||
|
return EMPTY_ADDRESS_SET;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run constant an analysis at each location in parallel
|
||||||
|
*
|
||||||
|
* @param program program
|
||||||
|
* @param locations points to analyze
|
||||||
|
* @param restrictedSet set to restrict analysis to, null if none
|
||||||
|
* @param maxThreads maximum number of threads to use
|
||||||
|
* @param monitor to cancel
|
||||||
|
* @return set of addresses covered during analysis
|
||||||
|
*
|
||||||
|
* @throws CancelledException if cancelled
|
||||||
|
* @throws InterruptedException if interrupted
|
||||||
|
* @throws Exception any exception
|
||||||
|
*/
|
||||||
|
protected AddressSetView runParallelAddressAnalysis(final Program program, final Set<Address> locations, final AddressSetView restrictedSet, int maxThreads,
|
||||||
|
final TaskMonitor monitor) throws CancelledException, InterruptedException, Exception {
|
||||||
|
|
||||||
|
monitor.checkCancelled();
|
||||||
|
|
||||||
|
final AddressSet analyzedSet = new AddressSet();
|
||||||
|
if (locations.isEmpty()) {
|
||||||
|
return analyzedSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
GThreadPool pool = AutoAnalysisManager.getSharedAnalsysThreadPool();
|
||||||
|
monitor.setMaximum(locations.size());
|
||||||
|
|
||||||
|
QCallback<Address, AddressSetView> callback = new QCallback<Address, AddressSetView>() {
|
||||||
|
@Override
|
||||||
|
public AddressSetView process(Address loc, TaskMonitor taskMonitor) {
|
||||||
|
synchronized (analyzedSet) {
|
||||||
|
if (analyzedSet.contains(loc)) {
|
||||||
|
taskMonitor.incrementProgress(1);
|
||||||
|
return EMPTY_ADDRESS_SET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
AddressSetView result = analyzeLocation(program, loc, restrictedSet, taskMonitor);
|
||||||
|
synchronized (analyzedSet) {
|
||||||
|
analyzedSet.add(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
taskMonitor.incrementProgress(1);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (CancelledException e) {
|
||||||
|
return null; // monitor was cancelled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// bound check thread limit
|
||||||
|
if (maxThreads > pool.getMaxThreadCount()) {
|
||||||
|
maxThreads = pool.getMaxThreadCount();
|
||||||
|
}
|
||||||
|
if (maxThreads < 1) {
|
||||||
|
maxThreads = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
ConcurrentQ<Address, AddressSetView> queue = new ConcurrentQBuilder<Address, AddressSetView>()
|
||||||
|
.setThreadPool(pool)
|
||||||
|
.setMaxInProgress(maxThreads)
|
||||||
|
.setMonitor(monitor)
|
||||||
|
.build(callback);
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
queue.add(locations);
|
||||||
|
|
||||||
|
queue.waitUntilDone();
|
||||||
|
|
||||||
|
return analyzedSet;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -155,126 +155,133 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest {
|
||||||
return super.evaluateContextBefore(context, instr);
|
return super.evaluateContextBefore(context, instr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Varnode regValue(VarnodeContext context, String regName) {
|
|
||||||
return context.getRegisterVarnodeValue(context.getRegister(regName));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
|
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
|
||||||
String loc = instr.getMinAddress().toString();
|
String loc = instr.getMinAddress().toString();
|
||||||
Varnode registerVarnode;
|
Varnode registerVarnode;
|
||||||
|
Long constVal;
|
||||||
|
boolean isBad = false;
|
||||||
|
|
||||||
switch (loc) {
|
switch(loc) {
|
||||||
case "00001010":
|
case "00001010":
|
||||||
// gp should be 0x14 + t9 offset space
|
// gp should be 0x14 + t9 offset space
|
||||||
registerVarnode = regValue(context, "gp");
|
registerVarnode = regValue(context,"gp");
|
||||||
assertTrue("symbolic value", context.isSymbol(registerVarnode));
|
assertTrue("symbolic value", context.isSymbol(registerVarnode));
|
||||||
assertEquals("(t9, 0x13b334, 4)", registerVarnode.toString());
|
assertEquals("(t9, 0x13b334, 4)", registerVarnode.toString());
|
||||||
// S3 should be S3 at entry
|
// S3 should be S3 at entry
|
||||||
registerVarnode = regValue(context, "s3");
|
registerVarnode = regValue(context,"s3");
|
||||||
assertTrue("register s3", context.isRegister(registerVarnode));
|
assertTrue("register s3", context.isRegister(registerVarnode));
|
||||||
assertEquals("s3", context.getRegister(registerVarnode).getName());
|
assertEquals("s3", context.getRegister(registerVarnode).getName());
|
||||||
break;
|
break;
|
||||||
case "0000102c":
|
case "0000102c":
|
||||||
// s1 restored from space 0x10(s0) space
|
// s1 restored from space 0x10(s0) space
|
||||||
registerVarnode = regValue(context, "s1");
|
registerVarnode = regValue(context,"s1");
|
||||||
assertTrue("constant value", registerVarnode.isConstant());
|
assertTrue("constant value", registerVarnode.isConstant());
|
||||||
assertEquals("(const, 0xa0b0c0d, 4)", registerVarnode.toString());
|
assertEquals("(const, 0xa0b0c0d, 4)", registerVarnode.toString());
|
||||||
break;
|
break;
|
||||||
case "00001030":
|
case "00001030":
|
||||||
// s1 restored from space 0x10(a1) space
|
// s1 restored from space 0x10(a1) space
|
||||||
registerVarnode = regValue(context, "s1");
|
registerVarnode = regValue(context,"s1");
|
||||||
assertTrue("symbolic value", registerVarnode.isConstant());
|
assertTrue("symbolic value", registerVarnode.isConstant());
|
||||||
assertEquals("(const, 0x12344567, 4)", registerVarnode.toString());
|
assertEquals("(const, 0x12344567, 4)", registerVarnode.toString());
|
||||||
break;
|
break;
|
||||||
case "00001034":
|
case "00001034":
|
||||||
// s1 restored from space 0x10(sp) space
|
// s1 restored from space 0x10(sp) space
|
||||||
registerVarnode = regValue(context, "s1");
|
registerVarnode = regValue(context,"s1");
|
||||||
assertTrue("symbolic value", context.isSymbol(registerVarnode));
|
assertTrue("symbolic value", context.isSymbol(registerVarnode));
|
||||||
assertEquals("(t9, 0x13b334, 4)", registerVarnode.toString());
|
assertEquals("(t9, 0x13b334, 4)", registerVarnode.toString());
|
||||||
break;
|
break;
|
||||||
case "00001038":
|
case "00001038":
|
||||||
// s1 restored from space 0x10(s2) space
|
// s1 restored from space 0x10(s2) space
|
||||||
registerVarnode = regValue(context, "s1");
|
registerVarnode = regValue(context,"s1");
|
||||||
//assertTrue("Still s1", registerVarnode.isRegister());
|
//assertTrue("Still s1", registerVarnode.isRegister());
|
||||||
boolean isBad = false;
|
constVal = context.getConstant(registerVarnode, null);
|
||||||
try {
|
isBad = constVal == null;
|
||||||
context.getConstant(registerVarnode, null);
|
assertTrue("Can get constant value", isBad);
|
||||||
}
|
break;
|
||||||
catch (NotFoundException e) {
|
case "00001040":
|
||||||
isBad = true;
|
// s1 restored from space 0x10(s2) space - stored a3
|
||||||
}
|
registerVarnode = regValue(context,"s1");
|
||||||
assertTrue("Can get constant value", isBad);
|
assertTrue("register s3", registerVarnode.isRegister());
|
||||||
break;
|
assertEquals("s3", context.getRegister(registerVarnode).getName());
|
||||||
case "00001040":
|
|
||||||
// s1 restored from space 0x10(s2) space - stored a3
|
|
||||||
registerVarnode = regValue(context, "s1");
|
|
||||||
assertTrue("register s3", registerVarnode.isRegister());
|
|
||||||
assertEquals("s3", context.getRegister(registerVarnode).getName());
|
|
||||||
|
|
||||||
Address lastSetLocation = context.getLastSetLocation(
|
Address lastSetLocation = context.getLastSetLocation(context.getRegisterVarnode(context.getRegister("s2")), null);
|
||||||
context.getRegisterVarnode(context.getRegister("s2")), null);
|
assertEquals("s2 last set", null, lastSetLocation);
|
||||||
assertEquals("s2 last set", null, lastSetLocation);
|
break;
|
||||||
break;
|
case "00001048":
|
||||||
case "00001048":
|
// s1 restored from space 0x10(s2) after s2 has been set again
|
||||||
// s1 restored from space 0x10(s2) after s2 has been set again
|
// it should no longer be s3 that was stored in another s2 relative space
|
||||||
// it should no longer be s3 that was stored in another s2 relative space
|
registerVarnode = regValue(context,"s1");
|
||||||
registerVarnode = regValue(context, "s1");
|
//assertTrue("Still s1", registerVarnode.isRegister());
|
||||||
//assertTrue("Still s1", registerVarnode.isRegister());
|
constVal = context.getConstant(registerVarnode, null);
|
||||||
isBad = false;
|
isBad = constVal == null;
|
||||||
try {
|
assertTrue("Can get constant value", isBad);
|
||||||
context.getConstant(registerVarnode, null);
|
break;
|
||||||
}
|
case "0000104c":
|
||||||
catch (NotFoundException e) {
|
// s1 restored from space 0x10(s2) after s2 has been set again
|
||||||
isBad = true;
|
// it should no longer be s3 that was stored in another s2 relative space
|
||||||
}
|
registerVarnode = regValue(context,"s2");
|
||||||
assertTrue("Can get constant value", isBad);
|
//assertTrue("Still s2", registerVarnode.isRegister());
|
||||||
break;
|
constVal = context.getConstant(registerVarnode, null);
|
||||||
case "0000104c":
|
isBad = constVal == null;
|
||||||
// s1 restored from space 0x10(s2) after s2 has been set again
|
assertTrue("Can get constant value", isBad);
|
||||||
// it should no longer be s3 that was stored in another s2 relative space
|
lastSetLocation = context.getLastSetLocation(context.getRegisterVarnode(context.getRegister("s2")), null);
|
||||||
registerVarnode = regValue(context, "s2");
|
assertEquals("s2 last set", 0x104cL, lastSetLocation.getOffset());
|
||||||
//assertTrue("Still s2", registerVarnode.isRegister());
|
break;
|
||||||
isBad = false;
|
case "00001054":
|
||||||
try {
|
// s1 restored from space 0x10(s2) after s2 has been set again
|
||||||
context.getConstant(registerVarnode, null);
|
// it should no longer be s3 that was stored in another s2 relative space
|
||||||
}
|
registerVarnode = regValue(context,"s1");
|
||||||
catch (NotFoundException e) {
|
//assertTrue("Still s1", registerVarnode.isRegister());
|
||||||
isBad = true;
|
//assertEquals(context.getRegister(registerVarnode).getName(),"s1");
|
||||||
}
|
constVal = context.getConstant(registerVarnode, null);
|
||||||
assertTrue("Can get constant value", isBad);
|
isBad = constVal == null;
|
||||||
lastSetLocation = context.getLastSetLocation(
|
assertTrue("Can get constant value", isBad);
|
||||||
context.getRegisterVarnode(context.getRegister("s2")), null);
|
break;
|
||||||
assertEquals("s2 last set", 0x104fL, lastSetLocation.getOffset());
|
|
||||||
break;
|
|
||||||
case "00001054":
|
|
||||||
// s1 restored from space 0x10(s2) after s2 has been set again
|
|
||||||
// it should no longer be s3 that was stored in another s2 relative space
|
|
||||||
registerVarnode = regValue(context, "s1");
|
|
||||||
//assertTrue("Still s1", registerVarnode.isRegister());
|
|
||||||
//assertEquals(context.getRegister(registerVarnode).getName(),"s1");
|
|
||||||
isBad = false;
|
|
||||||
try {
|
|
||||||
context.getConstant(registerVarnode, null);
|
|
||||||
}
|
|
||||||
catch (NotFoundException e) {
|
|
||||||
isBad = true;
|
|
||||||
}
|
|
||||||
assertTrue("Can get constant value", isBad);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return super.evaluateContext(context, instr);
|
return super.evaluateContext(context, instr);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
setRegister(addr("0x1000"), "s1", 0);
|
setRegister(addr("0x1000"), "s1", 0);
|
||||||
SymbolicPropogator symEval = new SymbolicPropogator(program);
|
SymbolicPropogator symEval = new SymbolicPropogator(program,true);
|
||||||
|
|
||||||
Function func = program.getFunctionManager().getFunctionAt(builder.addr(0x1000));
|
Function func = program.getFunctionManager().getFunctionAt(builder.addr(0x1000));
|
||||||
|
|
||||||
symEval.flowConstants(codeStart, func.getBody(), eval, true, TaskMonitor.DUMMY);
|
symEval.flowConstants(codeStart, func.getBody(), eval, true, TaskMonitor.DUMMY);
|
||||||
|
|
||||||
Value registerValue = symEval.getRegisterValue(addr("0x1010"), null);
|
Value registerValue;
|
||||||
|
|
||||||
|
// get gp at start of instruction
|
||||||
|
registerValue = regValue(symEval, addr("0x1010"), "gp");
|
||||||
|
assertNotNull(registerValue);
|
||||||
|
assertTrue(registerValue.isRegisterRelativeValue());
|
||||||
|
assertEquals(registerValue.getRelativeRegister().getName(), "t9");
|
||||||
|
assertEquals(registerValue.getValue(), 0x13b334L);
|
||||||
|
|
||||||
|
// get s1 at start of instruction
|
||||||
|
registerValue = regValue(symEval, addr("0x1034"), "s1");
|
||||||
|
assertNotNull(registerValue);
|
||||||
|
assertFalse(registerValue.isRegisterRelativeValue());
|
||||||
|
assertEquals(registerValue.getValue(), 0x12344567L);
|
||||||
|
|
||||||
|
// get s1 at end of instruction
|
||||||
|
registerValue = regEndValue(symEval, addr("0x1034"), "s1");
|
||||||
|
assertNotNull(registerValue);
|
||||||
|
assertTrue(registerValue.isRegisterRelativeValue());
|
||||||
|
assertEquals(registerValue.getRelativeRegister().getName(), "t9");
|
||||||
|
assertEquals(registerValue.getValue(), 0x13b334L);
|
||||||
|
|
||||||
|
// get sp at end of instruction
|
||||||
|
registerValue = regValue(symEval, addr("0x1058"), "sp");
|
||||||
|
assertNotNull(registerValue);
|
||||||
|
assertTrue(registerValue.isRegisterRelativeValue());
|
||||||
|
assertEquals(registerValue.getRelativeRegister().getName(), "sp");
|
||||||
|
assertEquals(-32, registerValue.getValue());
|
||||||
|
|
||||||
|
// TODO: should be 0 at end
|
||||||
|
// registerValue = regEndValue(symEval, addr("0x1058"), "sp");
|
||||||
|
// assertEquals(0, registerValue.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -543,6 +550,22 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest {
|
||||||
context.setRegisterValue(a, a.add(12), new RegisterValue(gp, BigInteger.valueOf(value)));
|
context.setRegisterValue(a, a.add(12), new RegisterValue(gp, BigInteger.valueOf(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Varnode regValue(VarnodeContext context, String regName) {
|
||||||
|
return context.getRegisterVarnodeValue(context.getRegister(regName));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value regValue(SymbolicPropogator symEval, Address addr, String regName) {
|
||||||
|
ProgramContext context = program.getProgramContext();
|
||||||
|
Register reg = context.getRegister(regName);
|
||||||
|
return symEval.getRegisterValue(addr, reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value regEndValue(SymbolicPropogator symEval, Address addr, String regName) {
|
||||||
|
ProgramContext context = program.getProgramContext();
|
||||||
|
Register reg = context.getRegister(regName);
|
||||||
|
return symEval.getEndRegisterValue(addr, reg);
|
||||||
|
}
|
||||||
|
|
||||||
private Address addr(String address) {
|
private Address addr(String address) {
|
||||||
return builder.addr(address);
|
return builder.addr(address);
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,16 @@ public class VarnodeTranslator {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get register given a register name
|
||||||
|
*
|
||||||
|
* @param name register name
|
||||||
|
* @return register
|
||||||
|
*/
|
||||||
|
public Register getRegister(String name) {
|
||||||
|
return language.getRegister(name);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all defined registers for the program this translator was created
|
* Get all defined registers for the program this translator was created
|
||||||
* with.
|
* with.
|
||||||
|
|
|
@ -73,30 +73,25 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
|
||||||
|
|
||||||
if (mnemonic.equals("pea")) {
|
if (mnemonic.equals("pea")) {
|
||||||
// retrieve the value pushed onto the stack
|
// retrieve the value pushed onto the stack
|
||||||
try {
|
Varnode stackValue = context.getValue(context.getStackVarnode(), this);
|
||||||
Varnode stackValue = context.getValue(context.getStackVarnode(), this);
|
Varnode value = context.getValue(stackValue, this);
|
||||||
Varnode value = context.getValue(stackValue, this);
|
if (value != null && value.isConstant()) {
|
||||||
if (value != null && value.isConstant()) {
|
long lval = value.getOffset();
|
||||||
long lval = value.getOffset();
|
Address refAddr = instr.getMinAddress().getNewAddress(lval);
|
||||||
Address refAddr = instr.getMinAddress().getNewAddress(lval);
|
if (lval <= 4096 || ((lval % 1024) == 0) || lval < 0 ||
|
||||||
if (lval <= 4096 || ((lval % 1024) == 0) || lval < 0 ||
|
lval == 0xffff || lval == 0xff00 || lval == 0xffffff ||
|
||||||
lval == 0xffff || lval == 0xff00 || lval == 0xffffff ||
|
lval == 0xff0000 || lval == 0xff00ff || lval == 0xffffffff ||
|
||||||
lval == 0xff0000 || lval == 0xff00ff || lval == 0xffffffff ||
|
lval == 0xffffff00 || lval == 0xffff0000 ||
|
||||||
lval == 0xffffff00 || lval == 0xffff0000 ||
|
lval == 0xff000000) {
|
||||||
lval == 0xff000000) {
|
return false;
|
||||||
return false;
|
}
|
||||||
}
|
if (program.getMemory().contains(refAddr)) {
|
||||||
if (program.getMemory().contains(refAddr)) {
|
if (instr.getOperandReferences(0).length == 0) {
|
||||||
if (instr.getOperandReferences(0).length == 0) {
|
instr.addOperandReference(0, refAddr, RefType.DATA,
|
||||||
instr.addOperandReference(0, refAddr, RefType.DATA,
|
SourceType.ANALYSIS);
|
||||||
SourceType.ANALYSIS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (NotFoundException e) {
|
|
||||||
// value not found doesn't matter
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (mnemonic.equals("lea")) {
|
if (mnemonic.equals("lea")) {
|
||||||
Register destReg = instr.getRegister(1);
|
Register destReg = instr.getRegister(1);
|
||||||
|
|
|
@ -799,7 +799,7 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
|
||||||
if (tmodeRegister != null && listing.getUndefinedDataAt(addr) != null) {
|
if (tmodeRegister != null && listing.getUndefinedDataAt(addr) != null) {
|
||||||
boolean inThumbMode = false;
|
boolean inThumbMode = false;
|
||||||
RegisterValue curvalue =
|
RegisterValue curvalue =
|
||||||
context.getRegisterValue(tmodeRegister, instruction.getMinAddress());
|
context.getRegisterValue(tmodeRegister);
|
||||||
if (curvalue != null && curvalue.hasValue()) {
|
if (curvalue != null && curvalue.hasValue()) {
|
||||||
inThumbMode = (curvalue.getUnsignedValue().intValue() == 1);
|
inThumbMode = (curvalue.getUnsignedValue().intValue() == 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -552,7 +552,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
|
||||||
|
|
||||||
if (isamode != null && listing.getUndefinedDataAt(addr) != null) {
|
if (isamode != null && listing.getUndefinedDataAt(addr) != null) {
|
||||||
boolean inM16Mode = false;
|
boolean inM16Mode = false;
|
||||||
RegisterValue curvalue = context.getRegisterValue(isamode, instruction.getMinAddress());
|
RegisterValue curvalue = context.getRegisterValue(isamode);
|
||||||
if (curvalue != null && curvalue.hasValue()) {
|
if (curvalue != null && curvalue.hasValue()) {
|
||||||
inM16Mode = (curvalue.getUnsignedValue().intValue() == 1);
|
inM16Mode = (curvalue.getUnsignedValue().intValue() == 1);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue