GP-4512 Constant propagation and stack analysis performance changes

This commit is contained in:
emteere 2025-05-08 17:35:25 -04:00 committed by ghidra1
parent df505c40a3
commit c396867209
12 changed files with 1724 additions and 1167 deletions

View file

@ -73,13 +73,27 @@ public class CallDepthChangeInfo {
/**
* 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
*/
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();
frameReg = program.getCompilerSpec().getStackPointer();
try {
initialize(func, func.getBody(), frameReg, TaskMonitor.DUMMY);
initialize(func, func.getBody(), frameReg, storeDepthAtEachInstuction, TaskMonitor.DUMMY);
}
catch (CancelledException e) {
throw new RuntimeException("Unexpected Exception", e);
@ -88,10 +102,8 @@ public class CallDepthChangeInfo {
/**
* Construct a new CallDepthChangeInfo object.
* @param func
* function to examine
* @param monitor
* monitor used to cancel the operation
* @param func function to examine
* @param monitor used to cancel the operation
*
* @throws CancelledException
* if the operation was canceled
@ -102,6 +114,8 @@ public class CallDepthChangeInfo {
/**
* 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 restrictSet set of addresses to restrict flow flowing to.
* @param frameReg register that is to have it's depth(value) change tracked
@ -116,34 +130,18 @@ public class CallDepthChangeInfo {
if (frameReg == null) {
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,
TaskMonitor monitor) throws CancelledException {
boolean storeDepthAtEachInstuction, TaskMonitor monitor) throws CancelledException {
changeMap = new DefaultIntPropertyMap("change");
depthMap = new DefaultIntPropertyMap("depth");
trans = new VarnodeTranslator(program);
symEval = new SymbolicPropogator(program);
symEval = new SymbolicPropogator(program,storeDepthAtEachInstuction);
symEval.setParamRefCheck(false);
symEval.setReturnRefCheck(false);
symEval.setStoredRefCheck(false);
@ -494,18 +492,14 @@ public class CallDepthChangeInfo {
@Override
public boolean evaluateContextBefore(VarnodeContext context, Instruction instr) {
Varnode stackRegVarnode = context.getRegisterVarnode(frameReg);
Varnode stackValue = null;
try {
stackValue = context.getValue(stackRegVarnode, true, this);
Varnode stackValue = context.getValue(stackRegVarnode, true, this);
if (stackValue != null && context.isSymbol(stackValue) &&
context.isStackSymbolicSpace(stackValue)) {
int stackPointerDepth = (int) stackValue.getOffset();
setDepth(instr, stackPointerDepth);
}
}
catch (NotFoundException e) {
// ignore
long stackPointerDepth = stackValue.getOffset();
int size = stackValue.getSize();
stackPointerDepth = (stackPointerDepth << 8 * (8 - size)) >> 8 * (8 - size);
setDepth(instr, (int) stackPointerDepth);
}
return false;
@ -621,25 +615,14 @@ public class CallDepthChangeInfo {
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 reg the register to get the depth of.
* @return the depth of the register at the address.
*/
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);
if (rValue == null) {
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 reg the register to get the representation of.
* @return the string representation of the register value.

View file

@ -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_LOCAL_OFFSET = -(64 * 1024); // max size of local reference space
private final static String X86_NAME = "x86";
private boolean dontCreateNewVariables = false;
private final boolean forceProcessing;
@ -54,6 +56,8 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
private Register stackReg;
private int purge = 0;
private boolean isX86 = false;
static String DEFAULT_FUNCTION_COMMENT = " FUNCTION";
/**
@ -102,6 +106,8 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
public boolean applyTo(Program p, TaskMonitor monitor) {
program = p;
isX86 = checkForX86(p);
int count = 0;
long numAddresses = entryPoints.getNumAddresses();
int numRanges = entryPoints.getNumAddressRanges();
@ -138,6 +144,11 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
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.
*
@ -245,7 +256,7 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
*
* @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 {
// check if this is a jump thunk through a function pointer
// if (checkThunk(func, monitor)) {
@ -271,7 +282,7 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
@Override
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
if (instr.getFlowType().isTerminal()) {
RegisterValue value = context.getRegisterValue(stackReg, instr.getMaxAddress());
RegisterValue value = context.getRegisterValue(stackReg);
if (value != null) {
BigInteger signedValue = value.getSignedValue();
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);
if (destReg != null) {
Varnode value = context.getRegisterVarnodeValue(destReg);
@ -320,18 +331,17 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
if (opIndex == -1) {
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!
if (instr.getMnemonicString().equals("POP")) {
if (isX86 && instr.getMnemonicString().equals("POP")) {
Register reg = instr.getRegister(opIndex);
if (reg != null && reg.getName().contains("BP")) {
return;
}
}
long extendedOffset =
extendOffset(address.getOffset(), stackReg.getBitLength());
Function func =
program.getFunctionManager().getFunctionContaining(instr.getMinAddress());
defineFuncVariable(func, instr, opIndex, (int) extendedOffset, sortedVariables);
long extendedOffset = extendOffset(address.getOffset(), stackReg.getBitLength());
defineFuncVariable(symEval, func, instr, opIndex, (int) extendedOffset, sortedVariables);
}
}
@ -342,9 +352,10 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
};
// 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) {
@ -623,11 +634,11 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
// 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) {
ReferenceManager refMgr = program.getReferenceManager();
int refSize = getRefSize(instr, opIndex);
int refSize = getRefSize(symEval, instr, opIndex);
try {
// don't create crazy offsets
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.
* @param symEval
*
* @param instr instruction being analyzed
* @param opIndex operand that has a stack reference.
*
* @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()) {
PcodeOp[] pcode = instr.getPcode();
PcodeOp[] pcode = symEval.getInstructionPcode(instr);
for (int i = pcode.length - 1; i >= 0; i--) {
if (pcode[i].getOpcode() == PcodeOp.LOAD) {
Varnode out = pcode[i].getOutput();
@ -810,7 +822,7 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand<Program> {
offset = minOffset;
}
else {
dt = Undefined.getUndefinedDataType(size);
dt = Undefined.getUndefinedDataType(refSize);
}
Variable var;

View file

@ -108,7 +108,6 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
final static HashSet<String> handledProcessors = new HashSet<String>();
protected String processorName = "Basic";
protected AddressSetView EMPTY_ADDRESS_SET = new AddressSet();
public ConstantPropagationAnalyzer() {
this("Basic");
@ -189,7 +188,8 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer {
int locationCount = locations.size();
monitor.initialize(locationCount);
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
unanalyzedSet.delete(resultSet);
}

View file

@ -15,21 +15,32 @@
*/
package ghidra.app.plugin.core.function;
import java.util.*;
import ghidra.app.cmd.function.FunctionStackAnalysisCmd;
import ghidra.app.cmd.function.NewFunctionStackAnalysisCmd;
import ghidra.app.services.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.cmd.BackgroundCommand;
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.listing.Function;
import ghidra.program.model.listing.Program;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public class StackVariableAnalyzer extends AbstractAnalyzer {
private static final String NAME = "Stack";
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 doCreateLocalStackVars = true;
private boolean doCreateStackParams = false;
@ -42,37 +53,88 @@ public class StackVariableAnalyzer extends AbstractAnalyzer {
}
@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;
// first split out all the function locations, make those the starts
// remove those from the bodies from the given set of addresses
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);
}
catch (Exception e) {
Msg.error(this, "caught exception", e);
e.printStackTrace();
}
return true;
}
@Override
public AddressSetView analyzeLocation(final Program program, Address start, AddressSetView set,
final TaskMonitor monitor) throws CancelledException {
BackgroundCommand<Program> cmd;
if (doNewStackAnalysis) {
cmd = new NewFunctionStackAnalysisCmd(set, doCreateStackParams, doCreateLocalStackVars,
cmd = new NewFunctionStackAnalysisCmd(new AddressSet(start, start), doCreateStackParams, doCreateLocalStackVars,
false);
}
else {
cmd = new FunctionStackAnalysisCmd(set, doCreateStackParams, doCreateLocalStackVars,
cmd = new FunctionStackAnalysisCmd(new AddressSet(start, start), doCreateStackParams, doCreateLocalStackVars,
false);
}
cmd.applyTo(program, monitor);
return true;
return EMPTY_ADDRESS_SET;
}
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;
/**
* 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());
}
}
return false;
}
// 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
public void registerOptions(Options options, Program program) {
options.registerOption(GhidraLanguagePropertyKeys.USE_NEW_FUNCTION_STACK_ANALYSIS,
!useOldStackAnalysisByDefault(program), null,
true, null,
"Use General Stack Reference Propogator (This works best on most processors)");
options.registerOption("Create Local Variables", doCreateLocalStackVars, null,
@ -80,18 +142,23 @@ public class StackVariableAnalyzer extends AbstractAnalyzer {
options.registerOption("Create Param Variables", doCreateStackParams, null,
"Create Function Parameter stack variables and references");
options.registerOption(MAX_THREAD_COUNT_OPTION_NAME, maxThreadCount, null,
MAX_THREAD_COUNT_OPTION_DESCRIPTION);
}
@Override
public void optionsChanged(Options options, Program program) {
doNewStackAnalysis =
options.getBoolean(GhidraLanguagePropertyKeys.USE_NEW_FUNCTION_STACK_ANALYSIS,
!useOldStackAnalysisByDefault(program));
true);
doCreateLocalStackVars =
options.getBoolean("Create Local Variables", doCreateLocalStackVars);
doCreateStackParams = options.getBoolean("Create Param Variables", doCreateStackParams);
maxThreadCount = options.getInt(MAX_THREAD_COUNT_OPTION_NAME, maxThreadCount);
}
}

View file

@ -15,9 +15,13 @@
*/
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.framework.options.Options;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
@ -31,6 +35,8 @@ public abstract class AbstractAnalyzer implements Analyzer {
private boolean isPrototype = false;
private AnalysisPriority priority = AnalysisPriority.LOW_PRIORITY;
protected static final AddressSetView EMPTY_ADDRESS_SET = new AddressSetViewAdapter();
protected AbstractAnalyzer(String name, String description, AnalyzerType type) {
this.name = name;
this.type = type;
@ -118,4 +124,95 @@ public abstract class AbstractAnalyzer implements Analyzer {
// 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;
}
}

View file

@ -155,14 +155,12 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest {
return super.evaluateContextBefore(context, instr);
}
private Varnode regValue(VarnodeContext context, String regName) {
return context.getRegisterVarnodeValue(context.getRegister(regName));
}
@Override
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
String loc = instr.getMinAddress().toString();
Varnode registerVarnode;
Long constVal;
boolean isBad = false;
switch(loc) {
case "00001010":
@ -197,13 +195,8 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest {
// s1 restored from space 0x10(s2) space
registerVarnode = regValue(context,"s1");
//assertTrue("Still s1", registerVarnode.isRegister());
boolean isBad = false;
try {
context.getConstant(registerVarnode, null);
}
catch (NotFoundException e) {
isBad = true;
}
constVal = context.getConstant(registerVarnode, null);
isBad = constVal == null;
assertTrue("Can get constant value", isBad);
break;
case "00001040":
@ -212,8 +205,7 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest {
assertTrue("register s3", registerVarnode.isRegister());
assertEquals("s3", context.getRegister(registerVarnode).getName());
Address lastSetLocation = context.getLastSetLocation(
context.getRegisterVarnode(context.getRegister("s2")), null);
Address lastSetLocation = context.getLastSetLocation(context.getRegisterVarnode(context.getRegister("s2")), null);
assertEquals("s2 last set", null, lastSetLocation);
break;
case "00001048":
@ -221,13 +213,8 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest {
// it should no longer be s3 that was stored in another s2 relative space
registerVarnode = regValue(context,"s1");
//assertTrue("Still s1", registerVarnode.isRegister());
isBad = false;
try {
context.getConstant(registerVarnode, null);
}
catch (NotFoundException e) {
isBad = true;
}
constVal = context.getConstant(registerVarnode, null);
isBad = constVal == null;
assertTrue("Can get constant value", isBad);
break;
case "0000104c":
@ -235,17 +222,11 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest {
// it should no longer be s3 that was stored in another s2 relative space
registerVarnode = regValue(context,"s2");
//assertTrue("Still s2", registerVarnode.isRegister());
isBad = false;
try {
context.getConstant(registerVarnode, null);
}
catch (NotFoundException e) {
isBad = true;
}
constVal = context.getConstant(registerVarnode, null);
isBad = constVal == null;
assertTrue("Can get constant value", isBad);
lastSetLocation = context.getLastSetLocation(
context.getRegisterVarnode(context.getRegister("s2")), null);
assertEquals("s2 last set", 0x104fL, lastSetLocation.getOffset());
lastSetLocation = context.getLastSetLocation(context.getRegisterVarnode(context.getRegister("s2")), null);
assertEquals("s2 last set", 0x104cL, lastSetLocation.getOffset());
break;
case "00001054":
// s1 restored from space 0x10(s2) after s2 has been set again
@ -253,13 +234,8 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest {
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;
}
constVal = context.getConstant(registerVarnode, null);
isBad = constVal == null;
assertTrue("Can get constant value", isBad);
break;
}
@ -268,13 +244,44 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest {
};
setRegister(addr("0x1000"), "s1", 0);
SymbolicPropogator symEval = new SymbolicPropogator(program);
SymbolicPropogator symEval = new SymbolicPropogator(program,true);
Function func = program.getFunctionManager().getFunctionAt(builder.addr(0x1000));
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
@ -543,6 +550,22 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest {
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) {
return builder.addr(address);
}

View file

@ -71,6 +71,16 @@ public class VarnodeTranslator {
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
* with.

View file

@ -73,7 +73,6 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
if (mnemonic.equals("pea")) {
// retrieve the value pushed onto the stack
try {
Varnode stackValue = context.getValue(context.getStackVarnode(), this);
Varnode value = context.getValue(stackValue, this);
if (value != null && value.isConstant()) {
@ -94,10 +93,6 @@ public class Motorola68KAnalyzer extends ConstantPropagationAnalyzer {
}
}
}
catch (NotFoundException e) {
// value not found doesn't matter
}
}
if (mnemonic.equals("lea")) {
Register destReg = instr.getRegister(1);
if (destReg == null) {

View file

@ -799,7 +799,7 @@ public class ArmAnalyzer extends ConstantPropagationAnalyzer {
if (tmodeRegister != null && listing.getUndefinedDataAt(addr) != null) {
boolean inThumbMode = false;
RegisterValue curvalue =
context.getRegisterValue(tmodeRegister, instruction.getMinAddress());
context.getRegisterValue(tmodeRegister);
if (curvalue != null && curvalue.hasValue()) {
inThumbMode = (curvalue.getUnsignedValue().intValue() == 1);
}

View file

@ -552,7 +552,7 @@ public class MipsAddressAnalyzer extends ConstantPropagationAnalyzer {
if (isamode != null && listing.getUndefinedDataAt(addr) != null) {
boolean inM16Mode = false;
RegisterValue curvalue = context.getRegisterValue(isamode, instruction.getMinAddress());
RegisterValue curvalue = context.getRegisterValue(isamode);
if (curvalue != null && curvalue.hasValue()) {
inM16Mode = (curvalue.getUnsignedValue().intValue() == 1);
}