From b30fa7792295875081a6ad6b1ee903c2b5565ee6 Mon Sep 17 00:00:00 2001
From: emteere <47253321+emteere@users.noreply.github.com>
Date: Tue, 19 Apr 2022 11:36:53 -0400
Subject: [PATCH] GP-1862_emteere changes for MIPS 64_32addr stack references
and stack depth following
---
.../app/cmd/function/CallDepthChangeInfo.java | 397 +-----------------
.../function/NewFunctionStackAnalysisCmd.java | 4 +-
.../core/function/StackDepthFieldFactory.java | 10 +-
.../ghidra/program/util/VarnodeContext.java | 21 +-
4 files changed, 41 insertions(+), 391 deletions(-)
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CallDepthChangeInfo.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CallDepthChangeInfo.java
index 2097ce1bf8..6116ed5393 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CallDepthChangeInfo.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CallDepthChangeInfo.java
@@ -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
terminalPoints = new ArrayList(); // list of points that are
- // terminal to this function
-
- Stack st = new Stack();
- 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 terminalPoints = new ArrayList(); // list of points that are
- // terminal to this function
-
- Stack st = new Stack();
- 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);
- }
-
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/NewFunctionStackAnalysisCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/NewFunctionStackAnalysisCmd.java
index 5458cbc354..b5111d8a58 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/NewFunctionStackAnalysisCmd.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/NewFunctionStackAnalysisCmd.java
@@ -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();
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/StackDepthFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/StackDepthFieldFactory.java
index 64c4168c84..a55b564afd 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/StackDepthFieldFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/StackDepthFieldFactory.java
@@ -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;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/VarnodeContext.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/VarnodeContext.java
index f918feadc9..24392535e9 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/VarnodeContext.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/VarnodeContext.java
@@ -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 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);
}
/**