Merge remote-tracking branch 'origin/GP-1862_emteere_MIPS_6432_stackrefs--SQUASHED' into patch

This commit is contained in:
Ryan Kurtz 2022-04-19 12:04:25 -04:00
commit 23467aca57
4 changed files with 41 additions and 391 deletions

View File

@ -169,22 +169,6 @@ public class CallDepthChangeInfo {
followFlows(func, restrictSet, monitor);
// try {
// CodeBlockIterator cbIter = new SimpleBlockModel(program).getCodeBlocksContaining(body, monitor);
// while (cbIter.hasNext()) {
// CodeBlock block = cbIter.next();
// codeBlocks.add(block);
// if (block.getFlowType().isCall()) {
// Instruction instr = program.getListing()
// .getInstructionContaining(block.getMaxAddress());
// if (instr != null) {
// callLocs.add(instr.getMinAddress());
// }
// }
// }
// computeDepthChange(monitor);
// } catch (UncomputableStackDepthException e) {
// }
}
public int getCallChange(Address addr) {
@ -236,8 +220,7 @@ public class CallDepthChangeInfo {
* depth cannot be determined, then return that the stack depth change is
* unknown.
*
* @param instr
* instruction to analyze
* @param instr instruction to analyze
*
* @return int change to stack depth if it can be determined,
* Function.UNKNOWN_STACK_DEPTH_CHANGE otherwise.
@ -413,21 +396,6 @@ public class CallDepthChangeInfo {
return false;
}
/**
* Get the default/assumed stack depth change for this language
*
* @param depth stack depth to return if the default is unknown for the language
* @return
*/
private int getDefaultStackDepthChange(int depth) {
PrototypeModel defaultModel = program.getCompilerSpec().getDefaultCallingConvention();
int callStackMod = defaultModel.getExtrapop();
int callStackShift = defaultModel.getStackshift();
if (callStackMod != PrototypeModel.UNKNOWN_EXTRAPOP && callStackShift >= 0) {
return callStackShift - callStackMod;
}
return depth;
}
/**
* Gets the stack depth change value that has been set at the indicated address.
@ -507,132 +475,6 @@ public class CallDepthChangeInfo {
return ipm.getPropertyIterator(addressSet);
}
/**
* Do a better job of tracking the stack by attempting to follow the data
* flow of the stack pointer as it moves in and out of other variables.
*
* @param program1 -
* program containing the function to analyze
* @param func -
* function to analyze stack pointer references
*/
public int smoothDepth(Program program1, Function func, TaskMonitor monitor) {
if (trans.supportsPcode()) {
return smoothPcodeDepth(program1, func, monitor);
}
int returnStackDepth = Function.INVALID_STACK_DEPTH_CHANGE;
// terminal points
ArrayList<Address> terminalPoints = new ArrayList<Address>(); // list of points that are
// terminal to this function
Stack<Object> st = new Stack<Object>();
st.push(func.getEntryPoint());
st.push(new Integer(0));
st.push(Boolean.TRUE);
ProcessorContextImpl procContext = new ProcessorContextImpl(program.getLanguage());
AddressSet undone = new AddressSet(func.getBody());
AddressSet badStackSet = new AddressSet(undone);
while (!st.empty()) {
Boolean stackOK = (Boolean) st.pop();
int stackPointerDepth = ((Integer) st.pop()).intValue();
Address loc = (Address) st.pop();
if (!undone.contains(loc)) {
continue;
}
// remove instruction from address set
undone.deleteRange(loc, loc);
Instruction instr = program1.getListing().getInstructionAt(loc);
if (instr == null) {
continue;
}
if (stackOK == Boolean.TRUE) {
this.setDepth(instr, stackPointerDepth);
}
// check for a frame setup
// if (checkFrameSetup(instr, stackPointerDepth, procContext)) {
// isFrameBased = true;
// }
// process any stack pointer manipulations
int instrChangeDepth =
this.getInstructionStackDepthChange(instr, procContext, stackPointerDepth);
if (instrChangeDepth != Function.UNKNOWN_STACK_DEPTH_CHANGE &&
instrChangeDepth != Function.INVALID_STACK_DEPTH_CHANGE) {
stackPointerDepth += instrChangeDepth;
}
else {
stackOK = Boolean.FALSE;
}
// if stack is OK at this instruction, remove from the bad stack set
if (stackOK == Boolean.TRUE) {
badStackSet.deleteRange(instr.getMinAddress(), instr.getMaxAddress());
}
// push any control flows that are still in address set
FlowType flow = instr.getFlowType();
if (!flow.isCall()) {
Address[] flows = instr.getFlows();
for (Address flow2 : flows) {
st.push(flow2);
st.push(new Integer(stackPointerDepth));
st.push(stackOK);
}
}
else {
// see if the info structure has the call depth
int callStackChange = getCallChange(instr.getMinAddress());
if (callStackChange == Function.UNKNOWN_STACK_DEPTH_CHANGE ||
callStackChange == Function.INVALID_STACK_DEPTH_CHANGE) {
stackOK = Boolean.FALSE;
}
else if (stackOK == Boolean.TRUE) {
stackPointerDepth += callStackChange;
}
}
Address fallThru = instr.getFallThrough();
if (fallThru != null) {
st.push(fallThru);
st.push(new Integer(stackPointerDepth));
st.push(stackOK);
}
if (flow.isTerminal()) {
int instrPurge =
getInstructionStackDepthChange(instr, procContext, returnStackDepth);
if (stackOK.booleanValue()) {
returnStackDepth = stackPointerDepth - instrPurge;
}
else {
returnStackDepth = -instrPurge;
terminalPoints.add(instr.getMinAddress());
}
// if (instr.getScalar(0) != null) {
// returnStackDepth = (int) -instr.getScalar(0)
// .getSignedValue();
// } else {
// if (stackOK == Boolean.TRUE) {
// returnStackDepth = stackPointerDepth;
// } else {
// terminalPoints.add(instr.getMinAddress());
// }
// }
}
}
// if (processTerminal) {
// backPropogateStackDepth(program, func, badStackSet, this,
// procContext, terminalPoints, monitor);
// }
return returnStackDepth;
}
/**
* Follow the flows of the subroutine, accumulating information about the
@ -642,7 +484,7 @@ public class CallDepthChangeInfo {
* function to analyze
* @param monitor
* monitor to provide feedback and cancel
* @throws CancelledException
* @throws CancelledException if monitor canceled
*/
private void followFlows(Function func, AddressSetView restrictSet, TaskMonitor monitor)
throws CancelledException {
@ -668,16 +510,16 @@ public class CallDepthChangeInfo {
Varnode stackValue = null;
try {
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
}
//Varnode stackValue = context.getRegisterVarnodeValue(stackReg, instr.getMinAddress(), true);
if (stackValue != null && context.isSymbol(stackValue) &&
stackValue.getAddress().getAddressSpace().getName().equals(
stackReg.getName())) {
int stackPointerDepth = (int) stackValue.getOffset();
setDepth(instr, stackPointerDepth);
}
return false;
}
@ -713,9 +555,9 @@ public class CallDepthChangeInfo {
private void checkForStackOffset(VarnodeContext context, Instruction instr,
Address address, int opIndex) {
AddressSpace space = address.getAddressSpace();
if (space.getName().startsWith("track_") ||
space.getName().equals(stackReg.getName())) {
String spaceName = address.getAddressSpace().getName();
if (spaceName.startsWith("track_") || context.isStackSpaceName(spaceName)) {
// TODO: what to do on a Symbolic reference
}
}
};
@ -735,55 +577,6 @@ public class CallDepthChangeInfo {
return;
}
// /**
// * Checks the indicated function in the program to determine if it is a jump thunk
// * through a function pointer.
// * @param func the function to check
// * @param monitor status monitor for indicating progress and allowing cancel.
// * @return true if check if this is a jump thunk through a function pointer
// */
// private boolean checkThunk(Function func, TaskMonitor monitor) {
// Instruction instr = program.getListing().getInstructionAt(func.getEntryPoint());
// if (instr == null) {
// return false;
// }
//
// FlowType type = instr.getFlowType();
// if (!type.isJump() || !type.isComputed()) {
// return false;
// }
//
// Address flows[] = instr.getFlows();
// if (flows != null && flows.length > 0) {
// return false;
// }
//
// Reference refs[] = instr.getReferencesFrom();
// if (refs == null || refs.length == 0) {
// return false;
// }
//
// Function indirFunc = program.getFunctionManager().getFunctionAt(refs[0].getToAddress());
// FunctionSignature fsig = null;
// int purge = Function.UNKNOWN_STACK_DEPTH_CHANGE;
// if (indirFunc != null) {
// fsig = indirFunc.getSignature();
// purge = indirFunc.getStackPurgeSize();
// }
// else {
// Data data = program.getListing().getDataAt(refs[0].getToAddress());
// if (data != null && data.isPointer() &&
// data.getDataType() instanceof FunctionDefinition) {
// FunctionDefinition fdef = (FunctionDefinition) data.getDataType();
// fsig = fdef;
// }
// }
// if (fsig == null) {
// return false;
// }
// func.setStackPurgeSize(purge);
// return true;
// }
public int getStackPurge() {
return stackPurge;
@ -882,170 +675,4 @@ public class CallDepthChangeInfo {
public String getRegValueRepresentation(Address addr, Register reg) {
return symEval.getRegisterValueRepresentation(addr, reg);
}
/**
* Create locals and parameters based on references involving purely the
* stack pointer. Pushes, Pops, and arithmetic manipulation of the stack
* pointer must be tracked.
*
* @param program1 -
* program containing the function to analyze
* @param func -
* function to analyze stack pointer references
*/
private int smoothPcodeDepth(Program program1, Function func, TaskMonitor monitor) {
int returnStackDepth = Function.INVALID_STACK_DEPTH_CHANGE;
ArrayList<Address> terminalPoints = new ArrayList<Address>(); // list of points that are
// terminal to this function
Stack<Object> st = new Stack<Object>();
st.push(func.getEntryPoint());
st.push(Integer.valueOf(0));
st.push(Boolean.TRUE);
ProcessorContextImpl procContext = new ProcessorContextImpl(program.getLanguage());
AddressSet undone = new AddressSet(func.getBody());
AddressSet badStackSet = new AddressSet(undone);
while (!st.empty()) {
Boolean stackOK = (Boolean) st.pop();
int stackPointerDepth = ((Integer) st.pop()).intValue();
Address loc = (Address) st.pop();
if (!undone.contains(loc)) {
continue;
}
// remove instruction from address set
undone.deleteRange(loc, loc);
Instruction instr = program1.getListing().getInstructionAt(loc);
if (instr == null) {
continue;
}
if (stackOK == Boolean.TRUE) {
this.setDepth(instr, stackPointerDepth);
}
// check for a frame setup
// if (checkFrameSetup(instr, stackPointerDepth, procContext)) {
// isFrameBased = true;
// }
// process any stack pointer manipulations
int instrChangeDepth =
this.getInstructionStackDepthChange(instr, procContext, stackPointerDepth);
if (instrChangeDepth != Function.UNKNOWN_STACK_DEPTH_CHANGE) {
stackPointerDepth += instrChangeDepth;
}
else {
stackOK = Boolean.FALSE;
}
// if stack is OK at this instruction, remove from the bad stack set
if (stackOK == Boolean.TRUE) {
badStackSet.deleteRange(instr.getMinAddress(), instr.getMaxAddress());
}
// push any control flows that are still in address set
FlowType flow = instr.getFlowType();
if (!flow.isCall()) {
Address[] flows = instr.getFlows();
for (Address flow2 : flows) {
st.push(flow2);
st.push(Integer.valueOf(stackPointerDepth));
st.push(stackOK);
}
}
else {
// see if the info structure has the call depth
int callStackChange = getCallPurge(instr);
if (callStackChange == Function.UNKNOWN_STACK_DEPTH_CHANGE) {
callStackChange = this.getCallChange(instr.getMinAddress());
}
if (callStackChange == Function.UNKNOWN_STACK_DEPTH_CHANGE) {
stackOK = Boolean.FALSE;
}
else if (stackOK == Boolean.TRUE) {
stackPointerDepth += callStackChange;
}
}
Address fallThru = instr.getFallThrough();
if (fallThru != null) {
st.push(fallThru);
st.push(new Integer(stackPointerDepth));
st.push(stackOK);
}
if (flow.isTerminal()) {
if (stackOK == Boolean.TRUE) {
returnStackDepth = stackPointerDepth;
}
else {
if (instr.getScalar(0) != null) {
returnStackDepth = (int) instr.getScalar(0).getSignedValue();
}
else {
terminalPoints.add(instr.getMinAddress());
}
}
}
}
// if (processTerminal) {
// backPropogateStackDepth(program, func, badStackSet, this,
// procContext, terminalPoints, monitor);
// }
return returnStackDepth;
}
/**
* @param instr
*/
private int getCallPurge(Instruction instr) {
// see if there is an override at this address
Integer override = overrideMap.get(instr.getMinAddress());
if (override != null) {
return override.intValue();
}
FlowType fType = instr.getFlowType();
Address[] flows;
if (fType.isComputed()) {
Reference refs[] = instr.getReferencesFrom();
flows = new Address[refs.length];
for (int ri = 0; ri < refs.length; ri++) {
Data data = program.getListing().getDataAt(refs[ri].getToAddress());
if (data != null && data.isPointer()) {
Reference pointerRef = data.getPrimaryReference(0);
if (pointerRef != null) {
flows[ri] = pointerRef.getToAddress();
}
}
}
}
else {
flows = instr.getFlows();
}
// try to find a call destination that the stack frame is known
for (Address flow : flows) {
if (flow == null) {
continue;
}
Function func = program.getListing().getFunctionAt(flow);
if (func != null) {
int purge = func.getStackPurgeSize();
if (func.isStackPurgeSizeValid() && purge != Function.UNKNOWN_STACK_DEPTH_CHANGE &&
purge != Function.INVALID_STACK_DEPTH_CHANGE) {
return purge;
}
}
}
return getDefaultStackDepthChange(Function.UNKNOWN_STACK_DEPTH_CHANGE);
}
}

View File

@ -298,7 +298,7 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand {
Address address, int opIndex) {
AddressSpace space = address.getAddressSpace();
String spaceName = space.getName();
if (spaceName.startsWith("track_") || spaceName.equals(stackReg.getName())) {
if (spaceName.startsWith("track_") || context.isStackSpaceName(spaceName)) {
if (opIndex == -1) {
opIndex = getStackOpIndex(context, instr, (int) address.getOffset());
// if didn't get the right opIndex, and has a delayslot, check for good stack ref
@ -576,7 +576,7 @@ public class NewFunctionStackAnalysisCmd extends BackgroundCommand {
continue;
}
String spaceName = vnode.getAddress().getAddressSpace().getName();
if (spaceName.startsWith("track_") || spaceName.equals(stackReg.getName())) {
if (spaceName.startsWith("track_") || context.isStackSpaceName(spaceName)) {
// opLocation = opIndex;
local_offset += (int) vnode.getOffset();
}

View File

@ -89,7 +89,7 @@ public class StackDepthFieldFactory extends FieldFactory {
//Register stackReg = cu.getProgram().getCompilerSpec().getStackPointer();
int depthChange = depth.getDepth(cu.getMinAddress());
String depthString = getDepthString(depthChange);
String depthString = getDepthString(depthChange, cu.isInDelaySlot());
// This can be used to display the value of any register symbolically flowing over the program.
// depthString = depth.getRegValueRepresentation(cu.getMinAddress(), cu.getProgram().getRegister("ESP"));
@ -113,8 +113,13 @@ public class StackDepthFieldFactory extends FieldFactory {
* @param depthChange
* @return
*/
private String getDepthString(int depthChange) {
private String getDepthString(int depthChange, boolean isInDelaySlot) {
if (isInDelaySlot) {
return ""; // if in delayslot, stack changes will be on main instruction
}
String stringDepth = "- ? -";
if (depthChange != Function.UNKNOWN_STACK_DEPTH_CHANGE &&
depthChange != Function.INVALID_STACK_DEPTH_CHANGE) {
if (depthChange > 0) {
@ -129,6 +134,7 @@ public class StackDepthFieldFactory extends FieldFactory {
stringDepth = filler.substring(len) + stringDepth;
}
}
return stringDepth;
}

View File

@ -316,6 +316,9 @@ public class VarnodeContext implements ProcessorContext {
private void setupValidSymbolicStackNames(Program program) {
// figure out what register is used for stack values
Register stackRegister = getStackRegister();
if (stackRegister == null) {
return;
}
validSymbolicStackNames.add(stackRegister.getName());
List<Register> childRegisters = stackRegister.getChildRegisters();
@ -325,13 +328,27 @@ public class VarnodeContext implements ProcessorContext {
}
/**
* Return true if this varnode is stored in the symbolic stack space
* Check if varnode is in the stack space
*
* @param varnode varnode to check
*
* @return true if this varnode is stored in the symbolic stack space
*/
public boolean isStackSymbolicSpace(Varnode varnode) {
// symbolic spaces are off of a register, find the space
AddressSpace regSpace = addrFactory.getAddressSpace(varnode.getSpace());
return validSymbolicStackNames.contains(regSpace.getName());
return isStackSpaceName(regSpace.getName());
}
/**
* Check if spaceName is associated with the stack
*
* @param spaceName of address space to check
* @return true if spaceName is associated with the stack space
*/
public boolean isStackSpaceName(String spaceName) {
return validSymbolicStackNames.contains(spaceName);
}
/**