mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +02:00
Merge branch 'GT-3090_NearPointerResolve' into GT-3090_16bit_analysis
This commit is contained in:
commit
06de0d46a0
24 changed files with 385 additions and 197 deletions
|
@ -273,8 +273,7 @@ public class CallDepthChangeInfo {
|
||||||
|
|
||||||
PcodeOp[] pcode = instr.getPcode();
|
PcodeOp[] pcode = instr.getPcode();
|
||||||
Varnode outVarNode = null;
|
Varnode outVarNode = null;
|
||||||
for (int i = 0; i < pcode.length; i++) {
|
for (PcodeOp op : pcode) {
|
||||||
PcodeOp op = pcode[i];
|
|
||||||
Varnode input0 = op.getInput(0);
|
Varnode input0 = op.getInput(0);
|
||||||
Varnode input1 = op.getInput(1);
|
Varnode input1 = op.getInput(1);
|
||||||
Varnode output = op.getOutput();
|
Varnode output = op.getOutput();
|
||||||
|
@ -317,9 +316,10 @@ public class CallDepthChangeInfo {
|
||||||
break;
|
break;
|
||||||
case PcodeOp.INT_AND: // Assume this is a stack alignment and do the and
|
case PcodeOp.INT_AND: // Assume this is a stack alignment and do the and
|
||||||
if (isStackPointer(input0)) {
|
if (isStackPointer(input0)) {
|
||||||
if (currentStackDepth != Function.UNKNOWN_STACK_DEPTH_CHANGE)
|
if (currentStackDepth != Function.UNKNOWN_STACK_DEPTH_CHANGE) {
|
||||||
possibleDepthChange =
|
possibleDepthChange =
|
||||||
(int) (currentStackDepth & input1.getOffset()) - currentStackDepth;
|
(int) (currentStackDepth & input1.getOffset()) - currentStackDepth;
|
||||||
|
}
|
||||||
outVarNode = output;
|
outVarNode = output;
|
||||||
}
|
}
|
||||||
else if (input0.equals(outVarNode)) {
|
else if (input0.equals(outVarNode)) {
|
||||||
|
@ -327,9 +327,10 @@ public class CallDepthChangeInfo {
|
||||||
outVarNode = output;
|
outVarNode = output;
|
||||||
}
|
}
|
||||||
else if (isStackPointer(input1)) {
|
else if (isStackPointer(input1)) {
|
||||||
if (currentStackDepth != Function.UNKNOWN_STACK_DEPTH_CHANGE)
|
if (currentStackDepth != Function.UNKNOWN_STACK_DEPTH_CHANGE) {
|
||||||
possibleDepthChange =
|
possibleDepthChange =
|
||||||
(int) (currentStackDepth & input0.getOffset()) - currentStackDepth;
|
(int) (currentStackDepth & input0.getOffset()) - currentStackDepth;
|
||||||
|
}
|
||||||
outVarNode = output;
|
outVarNode = output;
|
||||||
}
|
}
|
||||||
else if (input1.equals(outVarNode)) {
|
else if (input1.equals(outVarNode)) {
|
||||||
|
@ -385,7 +386,7 @@ public class CallDepthChangeInfo {
|
||||||
|
|
||||||
// TODO: Modify return by normal stack shift....
|
// TODO: Modify return by normal stack shift....
|
||||||
if (flowType.isTerminal()) {
|
if (flowType.isTerminal()) {
|
||||||
depthChange -= program.getCompilerSpec().getCallStackShift();
|
depthChange -= program.getCompilerSpec().getDefaultCallingConvention().getStackshift();
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the current stack depth is still bad, don't return a depth change.
|
// if the current stack depth is still bad, don't return a depth change.
|
||||||
|
@ -419,8 +420,9 @@ public class CallDepthChangeInfo {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private int getDefaultStackDepthChange(int depth) {
|
private int getDefaultStackDepthChange(int depth) {
|
||||||
int callStackMod = program.getCompilerSpec().getCallStackMod();
|
PrototypeModel defaultModel = program.getCompilerSpec().getDefaultCallingConvention();
|
||||||
int callStackShift = program.getCompilerSpec().getCallStackShift();
|
int callStackMod = defaultModel.getExtrapop();
|
||||||
|
int callStackShift = defaultModel.getStackshift();
|
||||||
if (callStackMod != PrototypeModel.UNKNOWN_EXTRAPOP && callStackShift >= 0) {
|
if (callStackMod != PrototypeModel.UNKNOWN_EXTRAPOP && callStackShift >= 0) {
|
||||||
return callStackShift - callStackMod;
|
return callStackShift - callStackMod;
|
||||||
}
|
}
|
||||||
|
@ -578,8 +580,8 @@ public class CallDepthChangeInfo {
|
||||||
FlowType flow = instr.getFlowType();
|
FlowType flow = instr.getFlowType();
|
||||||
if (!flow.isCall()) {
|
if (!flow.isCall()) {
|
||||||
Address[] flows = instr.getFlows();
|
Address[] flows = instr.getFlows();
|
||||||
for (int i = 0; i < flows.length; i++) {
|
for (Address flow2 : flows) {
|
||||||
st.push(flows[i]);
|
st.push(flow2);
|
||||||
st.push(new Integer(stackPointerDepth));
|
st.push(new Integer(stackPointerDepth));
|
||||||
st.push(stackOK);
|
st.push(stackOK);
|
||||||
}
|
}
|
||||||
|
@ -653,7 +655,7 @@ public class CallDepthChangeInfo {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int purge = (short) program.getCompilerSpec().getCallStackMod();
|
int purge = (short) program.getCompilerSpec().getDefaultCallingConvention().getExtrapop();
|
||||||
final boolean possiblePurge = purge == -1 || purge > 3200 || purge < -3200;
|
final boolean possiblePurge = purge == -1 || purge > 3200 || purge < -3200;
|
||||||
|
|
||||||
// follow all flows building up context
|
// follow all flows building up context
|
||||||
|
@ -948,8 +950,8 @@ public class CallDepthChangeInfo {
|
||||||
FlowType flow = instr.getFlowType();
|
FlowType flow = instr.getFlowType();
|
||||||
if (!flow.isCall()) {
|
if (!flow.isCall()) {
|
||||||
Address[] flows = instr.getFlows();
|
Address[] flows = instr.getFlows();
|
||||||
for (int i = 0; i < flows.length; i++) {
|
for (Address flow2 : flows) {
|
||||||
st.push(flows[i]);
|
st.push(flow2);
|
||||||
st.push(new Integer(stackPointerDepth));
|
st.push(new Integer(stackPointerDepth));
|
||||||
st.push(stackOK);
|
st.push(stackOK);
|
||||||
}
|
}
|
||||||
|
@ -1027,11 +1029,11 @@ public class CallDepthChangeInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to find a call destination that the stack frame is known
|
// try to find a call destination that the stack frame is known
|
||||||
for (int i = 0; i < flows.length; i++) {
|
for (Address flow : flows) {
|
||||||
if (flows[i] == null) {
|
if (flow == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Function func = program.getListing().getFunctionAt(flows[i]);
|
Function func = program.getListing().getFunctionAt(flow);
|
||||||
if (func != null) {
|
if (func != null) {
|
||||||
int purge = func.getStackPurgeSize();
|
int purge = func.getStackPurgeSize();
|
||||||
if (func.isStackPurgeSizeValid() && purge != Function.UNKNOWN_STACK_DEPTH_CHANGE &&
|
if (func.isStackPurgeSizeValid() && purge != Function.UNKNOWN_STACK_DEPTH_CHANGE &&
|
||||||
|
|
|
@ -17,15 +17,16 @@ package ghidra.app.cmd.function;
|
||||||
|
|
||||||
import ghidra.framework.cmd.BackgroundCommand;
|
import ghidra.framework.cmd.BackgroundCommand;
|
||||||
import ghidra.framework.model.DomainObject;
|
import ghidra.framework.model.DomainObject;
|
||||||
import ghidra.program.model.address.AddressSet;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.address.AddressSetView;
|
|
||||||
import ghidra.program.model.lang.Processor;
|
import ghidra.program.model.lang.Processor;
|
||||||
|
import ghidra.program.model.lang.PrototypeModel;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
|
import ghidra.program.model.mem.MemoryAccessException;
|
||||||
import ghidra.program.model.scalar.Scalar;
|
import ghidra.program.model.scalar.Scalar;
|
||||||
import ghidra.program.model.symbol.FlowType;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.program.model.symbol.Reference;
|
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
import ghidra.util.exception.InvalidInputException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -34,13 +35,17 @@ import ghidra.util.task.TaskMonitor;
|
||||||
public class FunctionPurgeAnalysisCmd extends BackgroundCommand {
|
public class FunctionPurgeAnalysisCmd extends BackgroundCommand {
|
||||||
private AddressSetView entryPoints;
|
private AddressSetView entryPoints;
|
||||||
private Program program;
|
private Program program;
|
||||||
|
private PrototypeModel[] nearFarModels = null;
|
||||||
|
|
||||||
|
private static final int STDCALL_FAR = 0;
|
||||||
|
private static final int CDECL_FAR = 1;
|
||||||
|
private static final int STDCALL_NEAR = 2;
|
||||||
|
private static final int CDECL_NEAR = 3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new command for analyzing the Stack.
|
* Constructs a new command for analyzing the Stack.
|
||||||
* @param entries and address set indicating the entry points of functions that have
|
* @param entries and address set indicating the entry points of functions that have
|
||||||
* stacks to be analyzed.
|
* stacks to be analyzed.
|
||||||
* @param forceProcessing flag to force processing of stack references even if the stack
|
|
||||||
* has already been defined.
|
|
||||||
*/
|
*/
|
||||||
public FunctionPurgeAnalysisCmd(AddressSetView entries) {
|
public FunctionPurgeAnalysisCmd(AddressSetView entries) {
|
||||||
super("Compute Function Purge", true, true, false);
|
super("Compute Function Purge", true, true, false);
|
||||||
|
@ -56,12 +61,16 @@ public class FunctionPurgeAnalysisCmd extends BackgroundCommand {
|
||||||
program = (Program) obj;
|
program = (Program) obj;
|
||||||
|
|
||||||
Processor processor = program.getLanguage().getProcessor();
|
Processor processor = program.getLanguage().getProcessor();
|
||||||
if (program.getLanguage().getDefaultSpace().getSize() > 32 ||
|
AddressSpace defaultSpace = program.getLanguage().getDefaultSpace();
|
||||||
|
if (defaultSpace.getSize() > 32 ||
|
||||||
!processor.equals(Processor.findOrPossiblyCreateProcessor("x86"))) {
|
!processor.equals(Processor.findOrPossiblyCreateProcessor("x86"))) {
|
||||||
Msg.error(this,
|
Msg.error(this,
|
||||||
"Unsupported operation for language " + program.getLanguage().getLanguageID());
|
"Unsupported operation for language " + program.getLanguage().getLanguageID());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (defaultSpace instanceof SegmentedAddressSpace) { // For 16-bit x86, prepare to establish near/fear calling convention models
|
||||||
|
setupNearFarModels();
|
||||||
|
}
|
||||||
|
|
||||||
AddressSetView set = entryPoints;
|
AddressSetView set = entryPoints;
|
||||||
|
|
||||||
|
@ -95,6 +104,52 @@ public class FunctionPurgeAnalysisCmd extends BackgroundCommand {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For x86 16-bit find the models stdcallnear, stdcallfar, cdeclnear, and cdeclfar so they can
|
||||||
|
* be applied at the same time function purge is set.
|
||||||
|
*/
|
||||||
|
private void setupNearFarModels() {
|
||||||
|
int countModels = 0;
|
||||||
|
nearFarModels = new PrototypeModel[4];
|
||||||
|
nearFarModels[0] = null;
|
||||||
|
nearFarModels[1] = null;
|
||||||
|
nearFarModels[2] = null;
|
||||||
|
nearFarModels[3] = null;
|
||||||
|
PrototypeModel[] models = program.getCompilerSpec().getCallingConventions();
|
||||||
|
for (PrototypeModel model : models) {
|
||||||
|
if (model.isMerged()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int pos = -1;
|
||||||
|
if (model.getStackshift() == 4) {
|
||||||
|
if (model.getExtrapop() == PrototypeModel.UNKNOWN_EXTRAPOP) {
|
||||||
|
pos = STDCALL_FAR;
|
||||||
|
}
|
||||||
|
else if (model.getExtrapop() == 4) {
|
||||||
|
pos = CDECL_FAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (model.getStackshift() == 2) {
|
||||||
|
if (model.getExtrapop() == PrototypeModel.UNKNOWN_EXTRAPOP) {
|
||||||
|
pos = STDCALL_NEAR;
|
||||||
|
}
|
||||||
|
else if (model.getExtrapop() == 2) {
|
||||||
|
pos = CDECL_NEAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pos >= 0) {
|
||||||
|
if (nearFarModels[pos] == null) {
|
||||||
|
nearFarModels[pos] = model;
|
||||||
|
countModels += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (countModels < 4) {
|
||||||
|
Msg.warn(this,
|
||||||
|
"FunctionPurgeAnalysis is missing full range of near/far prototype models");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyze a function to build a stack frame based on stack references.
|
* Analyze a function to build a stack frame based on stack references.
|
||||||
* @param function function to be analyzed
|
* @param function function to be analyzed
|
||||||
|
@ -104,39 +159,120 @@ public class FunctionPurgeAnalysisCmd extends BackgroundCommand {
|
||||||
*/
|
*/
|
||||||
private void analyzeFunction(Function function, TaskMonitor monitor) throws CancelledException {
|
private void analyzeFunction(Function function, TaskMonitor monitor) throws CancelledException {
|
||||||
|
|
||||||
int purge = -1;
|
if (function == null) {
|
||||||
|
return;
|
||||||
if (function != null) {
|
|
||||||
purge = function.getStackPurgeSize();
|
|
||||||
}
|
}
|
||||||
|
int purge = function.getStackPurgeSize();
|
||||||
if (purge == -1 || purge > 128 || purge < -128) {
|
if (purge == -1 || purge > 128 || purge < -128) {
|
||||||
purge = locatePurgeReturn(program, function, monitor);
|
Instruction purgeInstruction = locatePurgeInstruction(function, monitor);
|
||||||
// if couldn't find it, don't set it!
|
if (purgeInstruction != null) {
|
||||||
if (purge != -1) {
|
purge = getPurgeValue(purgeInstruction);
|
||||||
function.setStackPurgeSize(purge);
|
// if couldn't find it, don't set it!
|
||||||
|
if (purge != -1) {
|
||||||
|
function.setStackPurgeSize(purge);
|
||||||
|
}
|
||||||
|
setPrototypeModel(function, purgeInstruction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int locatePurgeReturn(Program program, Function func, TaskMonitor monitor) {
|
private void setPrototypeModel(Function function, Instruction purgeInstruction) {
|
||||||
AddressSetView body = func.getBody();
|
if (nearFarModels == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (purgeInstruction.getFlowType().isCall()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (function.getSignatureSource() != SourceType.DEFAULT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PrototypeModel model = null;
|
||||||
|
try {
|
||||||
|
byte val = purgeInstruction.getBytes()[0];
|
||||||
|
if (val == (byte) 0xc3) {
|
||||||
|
model = nearFarModels[CDECL_NEAR];
|
||||||
|
}
|
||||||
|
else if (val == (byte) 0xcb) {
|
||||||
|
model = nearFarModels[CDECL_FAR];
|
||||||
|
}
|
||||||
|
else if (val == (byte) 0xc2) {
|
||||||
|
model = nearFarModels[STDCALL_NEAR];
|
||||||
|
}
|
||||||
|
else if (val == (byte) 0xca) {
|
||||||
|
model = nearFarModels[STDCALL_FAR];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (MemoryAccessException e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (model == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
function.setCallingConvention(model.getName());
|
||||||
|
}
|
||||||
|
catch (InvalidInputException e) {
|
||||||
|
// Ignore if we can't change it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int returnPurge = findReturnPurge(program, body);
|
private Instruction locatePurgeInstruction(Function func, TaskMonitor monitor) {
|
||||||
if (returnPurge != -1) {
|
AddressSetView body = func.getBody();
|
||||||
return returnPurge;
|
Instruction purgeInstruction;
|
||||||
|
|
||||||
|
purgeInstruction = findPurgeInstruction(body);
|
||||||
|
if (purgeInstruction != null) {
|
||||||
|
return purgeInstruction;
|
||||||
}
|
}
|
||||||
|
|
||||||
// look harder, maybe something wrong with body, compute with flow.
|
// look harder, maybe something wrong with body, compute with flow.
|
||||||
body = CreateFunctionCmd.getFunctionBody(program, func.getEntryPoint(), monitor);
|
body = CreateFunctionCmd.getFunctionBody(program, func.getEntryPoint(), monitor);
|
||||||
returnPurge = findReturnPurge(program, body);
|
return findPurgeInstruction(body);
|
||||||
|
|
||||||
return returnPurge;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int findReturnPurge(Program program, AddressSetView body) {
|
/**
|
||||||
int tempPurge;
|
* Given a terminating instruction, discover the purge value encoded in it
|
||||||
|
* @param instr is the terminating instruction
|
||||||
|
* @return the purge value (or -1 if a value can't be found)
|
||||||
|
*/
|
||||||
|
private int getPurgeValue(Instruction instr) {
|
||||||
|
if (instr.getFlowType().isCall()) {
|
||||||
|
// is an override call-return, terminal/call
|
||||||
|
// find a reference to a function, and take it's purge
|
||||||
|
Reference[] referencesFrom = instr.getReferencesFrom();
|
||||||
|
for (Reference reference : referencesFrom) {
|
||||||
|
if (reference.getReferenceType().isFlow()) {
|
||||||
|
Function functionAt =
|
||||||
|
program.getFunctionManager().getFunctionAt(reference.getToAddress());
|
||||||
|
// don't take the purge of a non-returning function
|
||||||
|
if (functionAt != null && !functionAt.hasNoReturn()) {
|
||||||
|
return functionAt.getStackPurgeSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int tempPurge = 0;
|
||||||
|
Scalar scalar = instr.getScalar(0);
|
||||||
|
if (scalar != null) {
|
||||||
|
tempPurge = (int) scalar.getSignedValue();
|
||||||
|
}
|
||||||
|
return tempPurge;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a terminating instruction in the given set of addresses with a purge encoded in it.
|
||||||
|
* This routine prefers a RET instruction, but if none is available, it will use a
|
||||||
|
* terminating CALL.
|
||||||
|
* @param body is the set of addresses to look through
|
||||||
|
* @return a terminating instruction or null
|
||||||
|
*/
|
||||||
|
private Instruction findPurgeInstruction(AddressSetView body) {
|
||||||
InstructionIterator iter = program.getListing().getInstructions(body, true);
|
InstructionIterator iter = program.getListing().getInstructions(body, true);
|
||||||
int count = 2048;
|
int count = 2048;
|
||||||
|
Instruction backupPurge = null;
|
||||||
while (iter.hasNext() && count > 0) {
|
while (iter.hasNext() && count > 0) {
|
||||||
count--;
|
count--;
|
||||||
Instruction instr = iter.next();
|
Instruction instr = iter.next();
|
||||||
|
@ -144,33 +280,15 @@ public class FunctionPurgeAnalysisCmd extends BackgroundCommand {
|
||||||
FlowType ftype = instr.getFlowType();
|
FlowType ftype = instr.getFlowType();
|
||||||
if (ftype.isTerminal()) {
|
if (ftype.isTerminal()) {
|
||||||
if (instr.getMnemonicString().compareToIgnoreCase("ret") == 0) {
|
if (instr.getMnemonicString().compareToIgnoreCase("ret") == 0) {
|
||||||
tempPurge = 0;
|
return instr;
|
||||||
Scalar scalar = instr.getScalar(0);
|
|
||||||
if (scalar != null) {
|
|
||||||
tempPurge = (int) scalar.getSignedValue();
|
|
||||||
return tempPurge;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
else if (ftype.isCall()) {
|
else if (ftype.isCall()) {
|
||||||
// is an override call-return, terminal/call
|
backupPurge = instr; // Use as last resort, if we can't find RET
|
||||||
// find a reference to a function, and take it's purge
|
|
||||||
Reference[] referencesFrom = instr.getReferencesFrom();
|
|
||||||
for (Reference reference : referencesFrom) {
|
|
||||||
if (reference.getReferenceType().isFlow()) {
|
|
||||||
Function functionAt = program.getFunctionManager().getFunctionAt(
|
|
||||||
reference.getToAddress());
|
|
||||||
// don't take the purge of a non-returning function
|
|
||||||
if (functionAt != null && !functionAt.hasNoReturn()) {
|
|
||||||
return functionAt.getStackPurgeSize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return backupPurge;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,8 +169,9 @@ public class FunctionResultStateStackAnalysisCmd extends BackgroundCommand {
|
||||||
|
|
||||||
// Process all the functions identified as needing stack analysis.
|
// Process all the functions identified as needing stack analysis.
|
||||||
// The list will have the lowest level functions analyzed first.
|
// The list will have the lowest level functions analyzed first.
|
||||||
int default_extraPop = program.getCompilerSpec().getCallStackMod();
|
PrototypeModel defaultModel = program.getCompilerSpec().getDefaultCallingConvention();
|
||||||
int default_stackshift = program.getCompilerSpec().getCallStackShift();
|
int default_extraPop = defaultModel.getExtrapop();
|
||||||
|
int default_stackshift = defaultModel.getStackshift();
|
||||||
|
|
||||||
while (!funcList.isEmpty()) {
|
while (!funcList.isEmpty()) {
|
||||||
monitor.checkCanceled();
|
monitor.checkCanceled();
|
||||||
|
@ -256,19 +257,22 @@ public class FunctionResultStateStackAnalysisCmd extends BackgroundCommand {
|
||||||
int storageSpaceID, RefType refType, TaskMonitor monitor1)
|
int storageSpaceID, RefType refType, TaskMonitor monitor1)
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
|
|
||||||
if (instrOpIndex < 0)
|
if (instrOpIndex < 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
Address fromAddr = op.getSeqnum().getTarget();
|
Address fromAddr = op.getSeqnum().getTarget();
|
||||||
Instruction instr = listing.getInstructionAt(fromAddr);
|
Instruction instr = listing.getInstructionAt(fromAddr);
|
||||||
if (instr == null)
|
if (instr == null) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
Address stackAddr = addrFactory.getStackSpace().getAddress(stackOffset);
|
Address stackAddr = addrFactory.getStackSpace().getAddress(stackOffset);
|
||||||
RefType rt = refType;
|
RefType rt = refType;
|
||||||
Reference ref = refMgr.getReference(fromAddr, stackAddr, instrOpIndex);
|
Reference ref = refMgr.getReference(fromAddr, stackAddr, instrOpIndex);
|
||||||
if (ref != null) {
|
if (ref != null) {
|
||||||
RefType existingRefType = ref.getReferenceType();
|
RefType existingRefType = ref.getReferenceType();
|
||||||
if (existingRefType == rt)
|
if (existingRefType == rt) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
if (existingRefType == RefType.READ || existingRefType == RefType.WRITE) {
|
if (existingRefType == RefType.READ || existingRefType == RefType.WRITE) {
|
||||||
rt = RefType.READ_WRITE;
|
rt = RefType.READ_WRITE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -892,14 +892,14 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
||||||
if (expSym.hasNoReturn()) {
|
if (expSym.hasNoReturn()) {
|
||||||
extFunc.setNoReturn(true);
|
extFunc.setNoReturn(true);
|
||||||
}
|
}
|
||||||
int stackShift = program.getCompilerSpec().getCallStackShift();
|
// TODO: This should not be done at time of import and should be done
|
||||||
if (stackShift == -1) {
|
// by a late running analyzer (e.g., stack analyzer) if no signature
|
||||||
stackShift = 0;
|
// has been established
|
||||||
}
|
// int stackShift = program.getCompilerSpec().getDefaultCallingConvention().getStackshift();
|
||||||
|
// if (stackShift == -1) {
|
||||||
|
// stackShift = 0;
|
||||||
|
// }
|
||||||
|
|
||||||
// TODO: This should not be done at time of import and should be done
|
|
||||||
// by a late running analyzer (e.g., stack analyzer) if no signature
|
|
||||||
// has been established
|
|
||||||
// int numParams = expSym.getPurge() / 4;
|
// int numParams = expSym.getPurge() / 4;
|
||||||
// if (numParams > 0) {
|
// if (numParams > 0) {
|
||||||
// // HACK: assumes specific stack-based x86 convention
|
// // HACK: assumes specific stack-based x86 convention
|
||||||
|
|
|
@ -1705,8 +1705,9 @@ public class SymbolicPropogator {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private int getDefaultStackDepthChange(Program prog, int depth) {
|
private int getDefaultStackDepthChange(Program prog, int depth) {
|
||||||
int callStackMod = prog.getCompilerSpec().getCallStackMod();
|
PrototypeModel defaultModel = prog.getCompilerSpec().getDefaultCallingConvention();
|
||||||
int callStackShift = prog.getCompilerSpec().getCallStackShift();
|
int callStackMod = defaultModel.getExtrapop();
|
||||||
|
int callStackShift = defaultModel.getStackshift();
|
||||||
if (callStackMod != PrototypeModel.UNKNOWN_EXTRAPOP) {
|
if (callStackMod != PrototypeModel.UNKNOWN_EXTRAPOP) {
|
||||||
return callStackShift;
|
return callStackShift;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,14 +46,17 @@ public class ResultsState {
|
||||||
|
|
||||||
private static final Iterator<ContextState> emptyContextStateIterator =
|
private static final Iterator<ContextState> emptyContextStateIterator =
|
||||||
new Iterator<ContextState>() {
|
new Iterator<ContextState>() {
|
||||||
|
@Override
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public ContextState next() {
|
public ContextState next() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void remove() {
|
public void remove() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -168,10 +171,12 @@ public class ResultsState {
|
||||||
|
|
||||||
stackGrowsNegative = program.getCompilerSpec().stackGrowsNegative();
|
stackGrowsNegative = program.getCompilerSpec().stackGrowsNegative();
|
||||||
Long stackOffset = currentPrototype.getStackParameterOffset();
|
Long stackOffset = currentPrototype.getStackParameterOffset();
|
||||||
if (stackOffset != null)
|
if (stackOffset != null) {
|
||||||
paramBaseStackOffset = stackOffset - currentPrototype.getStackshift();
|
paramBaseStackOffset = stackOffset - currentPrototype.getStackshift();
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
paramBaseStackOffset = null;
|
paramBaseStackOffset = null;
|
||||||
|
}
|
||||||
|
|
||||||
todoList.add(new BranchDestination(null, entryPt, entryState));
|
todoList.add(new BranchDestination(null, entryPt, entryState));
|
||||||
}
|
}
|
||||||
|
@ -253,9 +258,10 @@ public class ResultsState {
|
||||||
currentState = null;
|
currentState = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, ">>> At " + nextSeq.getTarget() + "/" + nextSeq.getTime() +
|
Msg.debug(this, ">>> At " + nextSeq.getTarget() + "/" + nextSeq.getTime() +
|
||||||
" " + instr);
|
" " + instr);
|
||||||
|
}
|
||||||
|
|
||||||
SequenceNumber lastSeq = flowFrom;
|
SequenceNumber lastSeq = flowFrom;
|
||||||
|
|
||||||
|
@ -272,9 +278,10 @@ public class ResultsState {
|
||||||
if (existingStates.containsKey(flowFrom)) {
|
if (existingStates.containsKey(flowFrom)) {
|
||||||
// TODO: We have processed this flow before
|
// TODO: We have processed this flow before
|
||||||
// TODO: Should we compare existingState with dest.initialState ?
|
// TODO: Should we compare existingState with dest.initialState ?
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Flow ignored - already processed: " +
|
Msg.debug(this, "Flow ignored - already processed: " +
|
||||||
flowFrom + " -> " + pcodeOp.getSeqnum());
|
flowFrom + " -> " + pcodeOp.getSeqnum());
|
||||||
|
}
|
||||||
instr = null; // signal - abort current flow
|
instr = null; // signal - abort current flow
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -284,9 +291,10 @@ public class ResultsState {
|
||||||
// Re-use existing state where register values match
|
// Re-use existing state where register values match
|
||||||
addState(flowFrom, otherEntryState);
|
addState(flowFrom, otherEntryState);
|
||||||
instr = null; // signal - abort current flow
|
instr = null; // signal - abort current flow
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Flow combined - similar state: " +
|
Msg.debug(this, "Flow combined - similar state: " +
|
||||||
flowFrom + " -> " + pcodeOp.getSeqnum());
|
flowFrom + " -> " + pcodeOp.getSeqnum());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -385,6 +393,7 @@ public class ResultsState {
|
||||||
|
|
||||||
private static Comparator<Object> CONTEXT_STATE_SET_SEQUENCE_COMPARATOR =
|
private static Comparator<Object> CONTEXT_STATE_SET_SEQUENCE_COMPARATOR =
|
||||||
new Comparator<Object>() {
|
new Comparator<Object>() {
|
||||||
|
@Override
|
||||||
public int compare(Object o1, Object o2) {
|
public int compare(Object o1, Object o2) {
|
||||||
ContextStateSet set = (ContextStateSet) o1;
|
ContextStateSet set = (ContextStateSet) o1;
|
||||||
SequenceNumber seq = (SequenceNumber) o2;
|
SequenceNumber seq = (SequenceNumber) o2;
|
||||||
|
@ -468,14 +477,16 @@ public class ResultsState {
|
||||||
private ContextState performInlineCall(Address inlineCallAddress, ContextState currentState,
|
private ContextState performInlineCall(Address inlineCallAddress, ContextState currentState,
|
||||||
TaskMonitor monitor) throws CancelledException {
|
TaskMonitor monitor) throws CancelledException {
|
||||||
|
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "*** Start Inline Call to " + inlineCallAddress + " ***");
|
Msg.debug(this, "*** Start Inline Call to " + inlineCallAddress + " ***");
|
||||||
|
}
|
||||||
ResultsState inlineState =
|
ResultsState inlineState =
|
||||||
new ResultsState(new SequenceNumber(inlineCallAddress, 0), null, currentState,
|
new ResultsState(new SequenceNumber(inlineCallAddress, 0), null, currentState,
|
||||||
maintainInstructionResults);
|
maintainInstructionResults);
|
||||||
inlineState.processFunction(monitor);
|
inlineState.processFunction(monitor);
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "*** End Inline Call to " + inlineCallAddress + " ***");
|
Msg.debug(this, "*** End Inline Call to " + inlineCallAddress + " ***");
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: How should multiple return states be handled ??
|
// TODO: How should multiple return states be handled ??
|
||||||
|
|
||||||
|
@ -746,9 +757,10 @@ public class ResultsState {
|
||||||
|
|
||||||
if (values[1].isConstant() && values[1].getOffset() == 0) {
|
if (values[1].isConstant() && values[1].getOffset() == 0) {
|
||||||
// TODO: This is a problem, since branch case may never be evaluated!
|
// TODO: This is a problem, since branch case may never be evaluated!
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Conditional Branch to " + inputs[0].getAddress() +
|
Msg.debug(this, "Conditional Branch to " + inputs[0].getAddress() +
|
||||||
" - Not taken due to false condition value");
|
" - Not taken due to false condition value");
|
||||||
|
}
|
||||||
break; // Fall-through case - assume that a pre-condition is steering the execution
|
break; // Fall-through case - assume that a pre-condition is steering the execution
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -762,16 +774,18 @@ public class ResultsState {
|
||||||
SequenceNumber dest =
|
SequenceNumber dest =
|
||||||
new SequenceNumber(seq.getTarget(), seq.getTime() +
|
new SequenceNumber(seq.getTarget(), seq.getTime() +
|
||||||
(int) inputs[0].getOffset());
|
(int) inputs[0].getOffset());
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Internal " +
|
Msg.debug(this, "Internal " +
|
||||||
(pcodeOp.getOpcode() == PcodeOp.CBRANCH ? "Conditional " : "") +
|
(pcodeOp.getOpcode() == PcodeOp.CBRANCH ? "Conditional " : "") +
|
||||||
"Branch to " + dest);
|
"Branch to " + dest);
|
||||||
|
}
|
||||||
todoList.add(new BranchDestination(pcodeOp.getSeqnum(), dest, currentState));
|
todoList.add(new BranchDestination(pcodeOp.getSeqnum(), dest, currentState));
|
||||||
}
|
}
|
||||||
else if (inputs[0].isAddress()) {
|
else if (inputs[0].isAddress()) {
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, (pcodeOp.getOpcode() == PcodeOp.CBRANCH ? "Conditional "
|
Msg.debug(this, (pcodeOp.getOpcode() == PcodeOp.CBRANCH ? "Conditional "
|
||||||
: "") + "Branch to " + inputs[0].getAddress());
|
: "") + "Branch to " + inputs[0].getAddress());
|
||||||
|
}
|
||||||
handleDirectFlow(pcodeOp, inputs[0].getAddress(), currentState, monitor);
|
handleDirectFlow(pcodeOp, inputs[0].getAddress(), currentState, monitor);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -786,8 +800,9 @@ public class ResultsState {
|
||||||
AddressSpace space = currentState.getEntryPoint().getTarget().getAddressSpace();
|
AddressSpace space = currentState.getEntryPoint().getTarget().getAddressSpace();
|
||||||
Address destAddr =
|
Address destAddr =
|
||||||
space.getAddress(getUnsignedOffset(values[0], space.getPointerSize()));
|
space.getAddress(getUnsignedOffset(values[0], space.getPointerSize()));
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Branch to " + destAddr);
|
Msg.debug(this, "Branch to " + destAddr);
|
||||||
|
}
|
||||||
handleDirectFlow(pcodeOp, destAddr, currentState, monitor);
|
handleDirectFlow(pcodeOp, destAddr, currentState, monitor);
|
||||||
}
|
}
|
||||||
else if (values[0].isAddress()) {
|
else if (values[0].isAddress()) {
|
||||||
|
@ -798,32 +813,36 @@ public class ResultsState {
|
||||||
currentState.getEntryPoint().getTarget().getAddressSpace();
|
currentState.getEntryPoint().getTarget().getAddressSpace();
|
||||||
Address destAddr =
|
Address destAddr =
|
||||||
space.getAddress(getUnsignedOffset(brOffset, space.getPointerSize()));
|
space.getAddress(getUnsignedOffset(brOffset, space.getPointerSize()));
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Indirect Branch to [" + values[0].getAddress() +
|
Msg.debug(this, "Indirect Branch to [" + values[0].getAddress() +
|
||||||
"] -> " + destAddr);
|
"] -> " + destAddr);
|
||||||
|
}
|
||||||
handleDirectFlow(pcodeOp, destAddr, currentState, monitor);
|
handleDirectFlow(pcodeOp, destAddr, currentState, monitor);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this,
|
Msg.debug(this,
|
||||||
"Indirect Branch to [" + values[0].toString(program.getLanguage()) +
|
"Indirect Branch to [" + values[0].toString(program.getLanguage()) +
|
||||||
"]");
|
"]");
|
||||||
|
}
|
||||||
handleIndirectFlow(pcodeOp, values[0], currentState, monitor);
|
handleIndirectFlow(pcodeOp, values[0], currentState, monitor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this,
|
Msg.debug(this,
|
||||||
"Indirect Branch to [" + values[0].toString(program.getLanguage()) +
|
"Indirect Branch to [" + values[0].toString(program.getLanguage()) +
|
||||||
"]");
|
"]");
|
||||||
|
}
|
||||||
handleIndirectFlow(pcodeOp, values[0], currentState, monitor);
|
handleIndirectFlow(pcodeOp, values[0], currentState, monitor);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case PcodeOp.CALL: // A call with absolute address
|
case PcodeOp.CALL: // A call with absolute address
|
||||||
if (inputs[0].isAddress()) {
|
if (inputs[0].isAddress()) {
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Call to " + inputs[0].getAddress());
|
Msg.debug(this, "Call to " + inputs[0].getAddress());
|
||||||
|
}
|
||||||
handleCall(pcodeOp, null, inputs[0].getAddress(), currentState, monitor);
|
handleCall(pcodeOp, null, inputs[0].getAddress(), currentState, monitor);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -839,8 +858,9 @@ public class ResultsState {
|
||||||
AddressSpace space = currentState.getEntryPoint().getTarget().getAddressSpace();
|
AddressSpace space = currentState.getEntryPoint().getTarget().getAddressSpace();
|
||||||
Address destAddr =
|
Address destAddr =
|
||||||
space.getAddress(getUnsignedOffset(values[0], space.getPointerSize()));
|
space.getAddress(getUnsignedOffset(values[0], space.getPointerSize()));
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Call to " + destAddr);
|
Msg.debug(this, "Call to " + destAddr);
|
||||||
|
}
|
||||||
handleCall(pcodeOp, indirectPtr, destAddr, currentState, monitor);
|
handleCall(pcodeOp, indirectPtr, destAddr, currentState, monitor);
|
||||||
}
|
}
|
||||||
else if (values[0].isAddress()) {
|
else if (values[0].isAddress()) {
|
||||||
|
@ -852,23 +872,26 @@ public class ResultsState {
|
||||||
currentState.getEntryPoint().getTarget().getAddressSpace();
|
currentState.getEntryPoint().getTarget().getAddressSpace();
|
||||||
Address destAddr =
|
Address destAddr =
|
||||||
space.getAddress(getUnsignedOffset(callOffset, space.getPointerSize()));
|
space.getAddress(getUnsignedOffset(callOffset, space.getPointerSize()));
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Indirect Call to [" + values[0].getAddress() +
|
Msg.debug(this, "Indirect Call to [" + values[0].getAddress() +
|
||||||
"] -> " + destAddr);
|
"] -> " + destAddr);
|
||||||
|
}
|
||||||
handleCall(pcodeOp, indirectPtr, destAddr, currentState, monitor);
|
handleCall(pcodeOp, indirectPtr, destAddr, currentState, monitor);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this,
|
Msg.debug(this,
|
||||||
"Indirect Call to [" + values[0].toString(program.getLanguage()) +
|
"Indirect Call to [" + values[0].toString(program.getLanguage()) +
|
||||||
"]");
|
"]");
|
||||||
|
}
|
||||||
handleIndirectCall(pcodeOp, indirectPtr, values[0], currentState, monitor);
|
handleIndirectCall(pcodeOp, indirectPtr, values[0], currentState, monitor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this,
|
Msg.debug(this,
|
||||||
"Indirect Call to [" + values[0].toString(program.getLanguage()) + "]");
|
"Indirect Call to [" + values[0].toString(program.getLanguage()) + "]");
|
||||||
|
}
|
||||||
handleIndirectCall(pcodeOp, indirectPtr, values[0], currentState, monitor);
|
handleIndirectCall(pcodeOp, indirectPtr, values[0], currentState, monitor);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -1737,8 +1760,9 @@ public class ResultsState {
|
||||||
BookmarkType.ERROR, "Instruction Expected", "Expected instruction at " + address);
|
BookmarkType.ERROR, "Instruction Expected", "Expected instruction at " + address);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Disassemble at " + address);
|
Msg.debug(this, "Disassemble at " + address);
|
||||||
|
}
|
||||||
DisassembleCommand cmd = new DisassembleCommand(address, null, true);
|
DisassembleCommand cmd = new DisassembleCommand(address, null, true);
|
||||||
cmd.applyTo(program, monitor);
|
cmd.applyTo(program, monitor);
|
||||||
monitor.checkCanceled();
|
monitor.checkCanceled();
|
||||||
|
@ -1772,8 +1796,9 @@ public class ResultsState {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (addRegister(reg, registersModified)) {
|
if (addRegister(reg, registersModified)) {
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "MODIFIED: " + reg + " = " + value);
|
Msg.debug(this, "MODIFIED: " + reg + " = " + value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Msg.debug(this, "SET: " + output + " = " + value);
|
Msg.debug(this, "SET: " + output + " = " + value);
|
||||||
|
@ -2068,10 +2093,11 @@ public class ResultsState {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (func == null) {
|
if (func == null) {
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Function not found at " + indirectPtr +
|
Msg.debug(this, "Function not found at " + indirectPtr +
|
||||||
" indirectly called from " + pcodeOp.getSeqnum().getTarget() +
|
" indirectly called from " + pcodeOp.getSeqnum().getTarget() +
|
||||||
" - call affects unknown");
|
" - call affects unknown");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2104,9 +2130,10 @@ public class ResultsState {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (func == null) {
|
if (func == null) {
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Function not found at " + destAddr + " called from " +
|
Msg.debug(this, "Function not found at " + destAddr + " called from " +
|
||||||
pcodeOp.getSeqnum().getTarget() + " - call affects unknown");
|
pcodeOp.getSeqnum().getTarget() + " - call affects unknown");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2133,10 +2160,11 @@ public class ResultsState {
|
||||||
// Must invalidate return varnode
|
// Must invalidate return varnode
|
||||||
DataType returnType = null;
|
DataType returnType = null;
|
||||||
if (func == null) {
|
if (func == null) {
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this,
|
Msg.debug(this,
|
||||||
"No function at " + destAddr + " called from " + calledFrom.getTarget() +
|
"No function at " + destAddr + " called from " + calledFrom.getTarget() +
|
||||||
" - default return/affects assumed");
|
" - default return/affects assumed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
returnType = func.getReturnType();
|
returnType = func.getReturnType();
|
||||||
|
@ -2147,8 +2175,9 @@ public class ResultsState {
|
||||||
|
|
||||||
VariableStorage retStorage = callingConvention.getReturnLocation(returnType, program);
|
VariableStorage retStorage = callingConvention.getReturnLocation(returnType, program);
|
||||||
Varnode varnode = null;
|
Varnode varnode = null;
|
||||||
if (retStorage.isValid() && (retStorage.getVarnodeCount()==1))
|
if (retStorage.isValid() && (retStorage.getVarnodeCount()==1)) {
|
||||||
varnode = retStorage.getFirstVarnode();
|
varnode = retStorage.getFirstVarnode();
|
||||||
|
}
|
||||||
if (varnode != null) {
|
if (varnode != null) {
|
||||||
// invalidate stored value
|
// invalidate stored value
|
||||||
currentState.store(varnode, getInvalidatedVarnode(calledFrom, varnode));
|
currentState.store(varnode, getInvalidatedVarnode(calledFrom, varnode));
|
||||||
|
@ -2183,9 +2212,10 @@ public class ResultsState {
|
||||||
if (purge == Function.UNKNOWN_STACK_DEPTH_CHANGE ||
|
if (purge == Function.UNKNOWN_STACK_DEPTH_CHANGE ||
|
||||||
purge == Function.INVALID_STACK_DEPTH_CHANGE) {
|
purge == Function.INVALID_STACK_DEPTH_CHANGE) {
|
||||||
String name = func != null ? func.getName() : ("at " + destAddr);
|
String name = func != null ? func.getName() : ("at " + destAddr);
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Stack purge unknown for function " + name + " called from " +
|
Msg.debug(this, "Stack purge unknown for function " + name + " called from " +
|
||||||
calledFrom.getTarget() + " - stack pointer invalidated");
|
calledFrom.getTarget() + " - stack pointer invalidated");
|
||||||
|
}
|
||||||
currentState.store(getStackPointerVarnode(),
|
currentState.store(getStackPointerVarnode(),
|
||||||
getInvalidatedVarnode(calledFrom, getStackPointerVarnode()));
|
getInvalidatedVarnode(calledFrom, getStackPointerVarnode()));
|
||||||
return;
|
return;
|
||||||
|
@ -2255,8 +2285,9 @@ public class ResultsState {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private static int getDefaultStackDepthChange(Program depthProgram, int depth) {
|
private static int getDefaultStackDepthChange(Program depthProgram, int depth) {
|
||||||
int callStackMod = depthProgram.getCompilerSpec().getCallStackMod();
|
PrototypeModel defaultModel = depthProgram.getCompilerSpec().getDefaultCallingConvention();
|
||||||
int callStackShift = depthProgram.getCompilerSpec().getCallStackShift();
|
int callStackMod = defaultModel.getExtrapop();
|
||||||
|
int callStackShift = defaultModel.getStackshift();
|
||||||
if (callStackMod != PrototypeModel.UNKNOWN_EXTRAPOP && callStackShift >= 0) {
|
if (callStackMod != PrototypeModel.UNKNOWN_EXTRAPOP && callStackShift >= 0) {
|
||||||
return callStackShift - callStackMod;
|
return callStackShift - callStackMod;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1138,7 +1138,7 @@ void Architecture::init(DocumentStorage &store)
|
||||||
fillinReadOnlyFromLoader();
|
fillinReadOnlyFromLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
Address SegmentedResolver::resolve(uintb val,int4 sz,const Address &point)
|
Address SegmentedResolver::resolve(uintb val,int4 sz,const Address &point,uintb &fullEncoding)
|
||||||
|
|
||||||
{
|
{
|
||||||
int4 innersz = segop->getInnerSize();
|
int4 innersz = segop->getInnerSize();
|
||||||
|
@ -1148,6 +1148,7 @@ Address SegmentedResolver::resolve(uintb val,int4 sz,const Address &point)
|
||||||
// (as with near pointers)
|
// (as with near pointers)
|
||||||
if (segop->getResolve().space != (AddrSpace *)0) {
|
if (segop->getResolve().space != (AddrSpace *)0) {
|
||||||
uintb base = glb->context->getTrackedValue(segop->getResolve(),point);
|
uintb base = glb->context->getTrackedValue(segop->getResolve(),point);
|
||||||
|
fullEncoding = (base << 8 * innersz) + (val & calc_mask(innersz));
|
||||||
vector<uintb> seginput;
|
vector<uintb> seginput;
|
||||||
seginput.push_back(val);
|
seginput.push_back(val);
|
||||||
seginput.push_back(base);
|
seginput.push_back(base);
|
||||||
|
@ -1156,6 +1157,7 @@ Address SegmentedResolver::resolve(uintb val,int4 sz,const Address &point)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else { // For anything else, consider it a "far" pointer
|
else { // For anything else, consider it a "far" pointer
|
||||||
|
fullEncoding = val;
|
||||||
int4 outersz = segop->getBaseSize();
|
int4 outersz = segop->getBaseSize();
|
||||||
uintb base = (val >> 8*innersz) & calc_mask(outersz);
|
uintb base = (val >> 8*innersz) & calc_mask(outersz);
|
||||||
val = val & calc_mask(innersz);
|
val = val & calc_mask(innersz);
|
||||||
|
|
|
@ -284,7 +284,7 @@ public:
|
||||||
/// \param sp is the segmented space
|
/// \param sp is the segmented space
|
||||||
/// \param sop is the segment operator
|
/// \param sop is the segment operator
|
||||||
SegmentedResolver(Architecture *g,AddrSpace *sp,SegmentOp *sop) { glb=g; spc=sp; segop=sop; }
|
SegmentedResolver(Architecture *g,AddrSpace *sp,SegmentOp *sop) { glb=g; spc=sp; segop=sop; }
|
||||||
virtual Address resolve(uintb val,int4 sz,const Address &point);
|
virtual Address resolve(uintb val,int4 sz,const Address &point,uintb &fullEncoding);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The Translate object keeps track of address ranges for which
|
/// The Translate object keeps track of address ranges for which
|
||||||
|
|
|
@ -269,8 +269,14 @@ bool CastStrategyC::isSubpieceCast(Datatype *outtype,Datatype *intype,uint4 offs
|
||||||
(outmeta!=TYPE_PTR)&&
|
(outmeta!=TYPE_PTR)&&
|
||||||
(outmeta!=TYPE_FLOAT))
|
(outmeta!=TYPE_FLOAT))
|
||||||
return false;
|
return false;
|
||||||
if ((inmeta==TYPE_PTR)&&((outmeta!=TYPE_INT) && (outmeta!=TYPE_UINT)))
|
if (inmeta==TYPE_PTR) {
|
||||||
return false; //other casts don't make sense for pointers
|
if (outmeta == TYPE_PTR) {
|
||||||
|
if (outtype->getSize() < intype->getSize())
|
||||||
|
return true; // Cast from far pointer to near pointer
|
||||||
|
}
|
||||||
|
if ((outmeta!=TYPE_INT) && (outmeta!=TYPE_UINT))
|
||||||
|
return false; //other casts don't make sense for pointers
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -827,14 +827,14 @@ int4 ActionShadowVar::apply(Funcdata &data)
|
||||||
/// \param rampoint will hold the Address of the resolved symbol
|
/// \param rampoint will hold the Address of the resolved symbol
|
||||||
/// \param data is the function being analyzed
|
/// \param data is the function being analyzed
|
||||||
/// \return the recovered symbol or NULL
|
/// \return the recovered symbol or NULL
|
||||||
SymbolEntry *ActionConstantPtr::isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op,Address &rampoint,Funcdata &data)
|
SymbolEntry *ActionConstantPtr::isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op,Address &rampoint,uintb &fullEncoding,Funcdata &data)
|
||||||
|
|
||||||
{
|
{
|
||||||
bool needexacthit;
|
bool needexacthit;
|
||||||
Architecture *glb = data.getArch();
|
Architecture *glb = data.getArch();
|
||||||
Varnode *outvn;
|
Varnode *outvn;
|
||||||
if (vn->getType()->getMetatype() == TYPE_PTR) { // Are we explicitly marked as a pointer
|
if (vn->getType()->getMetatype() == TYPE_PTR) { // Are we explicitly marked as a pointer
|
||||||
rampoint = glb->resolveConstant(spc,vn->getOffset(),vn->getSize(),op->getAddr());
|
rampoint = glb->resolveConstant(spc,vn->getOffset(),vn->getSize(),op->getAddr(),fullEncoding);
|
||||||
needexacthit = false;
|
needexacthit = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -881,7 +881,7 @@ SymbolEntry *ActionConstantPtr::isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op
|
||||||
// Check if the constant looks like a single bit or mask
|
// Check if the constant looks like a single bit or mask
|
||||||
if (bit_transitions(vn->getOffset(),vn->getSize()) < 3)
|
if (bit_transitions(vn->getOffset(),vn->getSize()) < 3)
|
||||||
return (SymbolEntry *)0;
|
return (SymbolEntry *)0;
|
||||||
rampoint = glb->resolveConstant(spc,vn->getOffset(),vn->getSize(),op->getAddr());
|
rampoint = glb->resolveConstant(spc,vn->getOffset(),vn->getSize(),op->getAddr(),fullEncoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rampoint.isInvalid()) return (SymbolEntry *)0;
|
if (rampoint.isInvalid()) return (SymbolEntry *)0;
|
||||||
|
@ -943,10 +943,11 @@ int4 ActionConstantPtr::apply(Funcdata &data)
|
||||||
else if ((opc == CPUI_PTRSUB)||(opc==CPUI_PTRADD))
|
else if ((opc == CPUI_PTRSUB)||(opc==CPUI_PTRADD))
|
||||||
continue;
|
continue;
|
||||||
Address rampoint;
|
Address rampoint;
|
||||||
entry = isPointer(rspc,vn,op,rampoint,data);
|
uintb fullEncoding;
|
||||||
|
entry = isPointer(rspc,vn,op,rampoint,fullEncoding,data);
|
||||||
vn->setPtrCheck(); // Set check flag AFTER searching for symbol
|
vn->setPtrCheck(); // Set check flag AFTER searching for symbol
|
||||||
if (entry != (SymbolEntry *)0) {
|
if (entry != (SymbolEntry *)0) {
|
||||||
data.spacebaseConstant(op,slot,entry,rampoint,vn->getOffset(),vn->getSize());
|
data.spacebaseConstant(op,slot,entry,rampoint,fullEncoding,vn->getSize());
|
||||||
if ((opc == CPUI_INT_ADD)&&(slot==1))
|
if ((opc == CPUI_INT_ADD)&&(slot==1))
|
||||||
data.opSwapInput(op,0,1);
|
data.opSwapInput(op,0,1);
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
|
@ -162,7 +162,7 @@ public:
|
||||||
/// \brief Check for constants, with pointer type, that correspond to global symbols
|
/// \brief Check for constants, with pointer type, that correspond to global symbols
|
||||||
class ActionConstantPtr : public Action {
|
class ActionConstantPtr : public Action {
|
||||||
int4 localcount; ///< Number of passes made for this function
|
int4 localcount; ///< Number of passes made for this function
|
||||||
static SymbolEntry *isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op,Address &rampoint,Funcdata &data);
|
static SymbolEntry *isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op,Address &rampoint,uintb &fullEncoding,Funcdata &data);
|
||||||
public:
|
public:
|
||||||
ActionConstantPtr(const string &g) : Action(0,"constantptr",g) {} ///< Constructor
|
ActionConstantPtr(const string &g) : Action(0,"constantptr",g) {} ///< Constructor
|
||||||
virtual void reset(Funcdata &data) { localcount = 0; }
|
virtual void reset(Funcdata &data) { localcount = 0; }
|
||||||
|
|
|
@ -333,7 +333,7 @@ void Funcdata::spacebaseConstant(PcodeOp *op,int4 slot,SymbolEntry *entry,const
|
||||||
outvn = outvn2;
|
outvn = outvn2;
|
||||||
opInsertBefore(extraop,op);
|
opInsertBefore(extraop,op);
|
||||||
}
|
}
|
||||||
if (sz != origsize) { // There is a change in size from address -> varnode
|
if (sz < origsize) { // The new constant is smaller than the original varnode, so we extend it
|
||||||
PcodeOp *zextop = newOp(1,op->getAddr());
|
PcodeOp *zextop = newOp(1,op->getAddr());
|
||||||
Varnode *outvn2 = newUniqueOut(origsize,zextop);
|
Varnode *outvn2 = newUniqueOut(origsize,zextop);
|
||||||
opSetOpcode(zextop,CPUI_INT_ZEXT); // Create an extension to get back to original varnode size
|
opSetOpcode(zextop,CPUI_INT_ZEXT); // Create an extension to get back to original varnode size
|
||||||
|
@ -341,6 +341,15 @@ void Funcdata::spacebaseConstant(PcodeOp *op,int4 slot,SymbolEntry *entry,const
|
||||||
opInsertBefore(zextop,op);
|
opInsertBefore(zextop,op);
|
||||||
outvn = outvn2;
|
outvn = outvn2;
|
||||||
}
|
}
|
||||||
|
else if (origsize < sz) { // The new constant is bigger than the original varnode, truncate it
|
||||||
|
PcodeOp *subOp = newOp(2,op->getAddr());
|
||||||
|
Varnode *outvn3 = newUniqueOut(origsize,subOp);
|
||||||
|
opSetOpcode(subOp,CPUI_SUBPIECE);
|
||||||
|
opSetInput(subOp,outvn,0);
|
||||||
|
opSetInput(subOp,newConstant(4, 0), 1); // Take least significant piece
|
||||||
|
opInsertBefore(subOp,op);
|
||||||
|
outvn = outvn3;
|
||||||
|
}
|
||||||
opSetInput(op,outvn,slot);
|
opSetInput(op,outvn,slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1403,7 +1403,8 @@ bool PrintC::pushPtrCharConstant(uintb val,const TypePointer *ct,const Varnode *
|
||||||
{
|
{
|
||||||
if (val==0) return false;
|
if (val==0) return false;
|
||||||
AddrSpace *spc = glb->getDefaultSpace();
|
AddrSpace *spc = glb->getDefaultSpace();
|
||||||
Address stringaddr = glb->resolveConstant(spc,val,ct->getSize(),op->getAddr());
|
uintb fullEncoding;
|
||||||
|
Address stringaddr = glb->resolveConstant(spc,val,ct->getSize(),op->getAddr(),fullEncoding);
|
||||||
if (stringaddr.isInvalid()) return false;
|
if (stringaddr.isInvalid()) return false;
|
||||||
if (!glb->symboltab->getGlobalScope()->isReadOnly(stringaddr,1,Address()))
|
if (!glb->symboltab->getGlobalScope()->isReadOnly(stringaddr,1,Address()))
|
||||||
return false; // Check that string location is readonly
|
return false; // Check that string location is readonly
|
||||||
|
|
|
@ -485,15 +485,27 @@ AddrSpace *AddrSpaceManager::getSpaceByShortcut(char sc) const
|
||||||
return (*iter).second;
|
return (*iter).second;
|
||||||
}
|
}
|
||||||
|
|
||||||
Address AddrSpaceManager::resolveConstant(AddrSpace *spc,uintb val,int4 sz,const Address &point) const
|
/// \brief Resolve a native constant into an Address
|
||||||
|
///
|
||||||
|
/// If there is a special resolver for the AddrSpace, this is invoked, otherwise
|
||||||
|
/// basic wordsize conversion and wrapping is performed. If the address encoding is
|
||||||
|
/// partial (as in a \e near pointer) and the full encoding can be recovered, it is passed back.
|
||||||
|
/// \param spc is the space to generate the address from
|
||||||
|
/// \param val is the constant encoding of the address
|
||||||
|
/// \param sz is the size of the constant encoding
|
||||||
|
/// \param point is the context address (for recovering full encoding info if necessary)
|
||||||
|
/// \param fullEncoding is used to pass back the recovered full encoding of the pointer
|
||||||
|
/// \return the formal Address associated with the encoding
|
||||||
|
Address AddrSpaceManager::resolveConstant(AddrSpace *spc,uintb val,int4 sz,const Address &point,uintb &fullEncoding) const
|
||||||
|
|
||||||
{
|
{
|
||||||
int4 ind = spc->getIndex();
|
int4 ind = spc->getIndex();
|
||||||
if (ind < resolvelist.size()) {
|
if (ind < resolvelist.size()) {
|
||||||
AddressResolver *resolve = resolvelist[ind];
|
AddressResolver *resolve = resolvelist[ind];
|
||||||
if (resolve != (AddressResolver *)0)
|
if (resolve != (AddressResolver *)0)
|
||||||
return resolve->resolve(val,sz,point);
|
return resolve->resolve(val,sz,point,fullEncoding);
|
||||||
}
|
}
|
||||||
|
fullEncoding = val;
|
||||||
val = AddrSpace::addressToByte(val,spc->getWordSize());
|
val = AddrSpace::addressToByte(val,spc->getWordSize());
|
||||||
val = spc->wrapOffset(val);
|
val = spc->wrapOffset(val);
|
||||||
return Address(spc,val);
|
return Address(spc,val);
|
||||||
|
|
|
@ -147,8 +147,9 @@ public:
|
||||||
/// \param val is constant to be resolved to an address
|
/// \param val is constant to be resolved to an address
|
||||||
/// \param sz is the size of \e val in context.
|
/// \param sz is the size of \e val in context.
|
||||||
/// \param point is the address at which this constant is being used
|
/// \param point is the address at which this constant is being used
|
||||||
|
/// \param fullEncoding is used to hold the full pointer encoding if \b val is a partial encoding
|
||||||
/// \return the resolved Address
|
/// \return the resolved Address
|
||||||
virtual Address resolve(uintb val,int4 sz,const Address &point)=0;
|
virtual Address resolve(uintb val,int4 sz,const Address &point,uintb &fullEncoding)=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief A virtual space \e stack space
|
/// \brief A virtual space \e stack space
|
||||||
|
@ -249,7 +250,7 @@ public:
|
||||||
AddrSpace *getConstantSpace(void) const; ///< Get the constant space
|
AddrSpace *getConstantSpace(void) const; ///< Get the constant space
|
||||||
Address getConstant(uintb val) const; ///< Get a constant encoded as an Address
|
Address getConstant(uintb val) const; ///< Get a constant encoded as an Address
|
||||||
Address createConstFromSpace(AddrSpace *spc) const; ///< Create a constant address encoding an address space
|
Address createConstFromSpace(AddrSpace *spc) const; ///< Create a constant address encoding an address space
|
||||||
Address resolveConstant(AddrSpace *spc,uintb val,int4 sz,const Address &point) const; ///< Resolve native constant to address
|
Address resolveConstant(AddrSpace *spc,uintb val,int4 sz,const Address &point,uintb &fullEncoding) const;
|
||||||
int4 numSpaces(void) const; ///< Get the number of address spaces for this processor
|
int4 numSpaces(void) const; ///< Get the number of address spaces for this processor
|
||||||
AddrSpace *getSpace(int4 i) const; ///< Get an address space via its index
|
AddrSpace *getSpace(int4 i) const; ///< Get an address space via its index
|
||||||
AddrSpace *getNextSpaceInOrder(AddrSpace *spc) const; ///< Get the next \e contiguous address space
|
AddrSpace *getNextSpaceInOrder(AddrSpace *spc) const; ///< Get the next \e contiguous address space
|
||||||
|
|
|
@ -1124,13 +1124,17 @@ Datatype *TypeSpacebase::getSubType(uintb off,uintb *newoff) const
|
||||||
|
|
||||||
{
|
{
|
||||||
Scope *scope = getMap();
|
Scope *scope = getMap();
|
||||||
// uintb unoff = (uintb)(intb)off; // Make sure this is a sign-extension
|
off = AddrSpace::byteToAddress(off, spaceid->getWordSize()); // Convert from byte offset to address unit
|
||||||
Address addr(spaceid,spaceid->wrapOffset(off));
|
// It should always be the case that given offset represents a full encoding of the
|
||||||
|
// pointer, so the point of context is unused
|
||||||
|
Address nullPoint;
|
||||||
|
uintb fullEncoding;
|
||||||
|
Address addr = glb->resolveConstant(spaceid, off, spaceid->getAddrSize(), nullPoint, fullEncoding);
|
||||||
SymbolEntry *smallest;
|
SymbolEntry *smallest;
|
||||||
|
|
||||||
// Assume symbol being referenced is address tied,
|
// Assume symbol being referenced is address tied,
|
||||||
// so we use empty usepoint
|
// so we use empty usepoint
|
||||||
smallest = scope->queryContainer(addr,1,Address());
|
smallest = scope->queryContainer(addr,1,nullPoint);
|
||||||
|
|
||||||
if (smallest == (SymbolEntry *)0) {
|
if (smallest == (SymbolEntry *)0) {
|
||||||
*newoff = 0;
|
*newoff = 0;
|
||||||
|
@ -1167,7 +1171,8 @@ int4 TypeSpacebase::compareDependency(const Datatype &op) const
|
||||||
Address TypeSpacebase::getAddress(uintb off,int4 sz,const Address &point) const
|
Address TypeSpacebase::getAddress(uintb off,int4 sz,const Address &point) const
|
||||||
|
|
||||||
{
|
{
|
||||||
return glb->resolveConstant(spaceid,off,sz,point);
|
uintb fullEncoding;
|
||||||
|
return glb->resolveConstant(spaceid,off,sz,point,fullEncoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TypeSpacebase::saveXml(ostream &s) const
|
void TypeSpacebase::saveXml(ostream &s) const
|
||||||
|
|
|
@ -80,7 +80,7 @@ public class DecompileCallback {
|
||||||
listing = program.getListing();
|
listing = program.getListing();
|
||||||
addrfactory = program.getAddressFactory();
|
addrfactory = program.getAddressFactory();
|
||||||
dtmanage = dt;
|
dtmanage = dt;
|
||||||
default_extrapop = pcodecompilerspec.getCallStackMod();
|
default_extrapop = pcodecompilerspec.getDefaultCallingConvention().getExtrapop();
|
||||||
cpool = null;
|
cpool = null;
|
||||||
nativeMessage = null;
|
nativeMessage = null;
|
||||||
debug = null;
|
debug = null;
|
||||||
|
|
|
@ -1393,8 +1393,8 @@ public class SleighLanguage implements Language {
|
||||||
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "index", element.getUnique());
|
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "index", element.getUnique());
|
||||||
|
|
||||||
int size = element.getSize(); // Size in bits
|
int size = element.getSize(); // Size in bits
|
||||||
if (size == 20) {
|
if (element instanceof SegmentedAddressSpace) {
|
||||||
// TODO: SegmentedAddressSpace shouldn't really return 20
|
// TODO: SegmentedAddressSpace shouldn't really return 21
|
||||||
size = 32;
|
size = 32;
|
||||||
}
|
}
|
||||||
if (size > 64) {
|
if (size > 64) {
|
||||||
|
|
|
@ -254,16 +254,6 @@ public class BasicCompilerSpec implements CompilerSpec {
|
||||||
ctxsetting.add(new ContextSetting(reg, value, begad, endad));
|
ctxsetting.add(new ContextSetting(reg, value, begad, endad));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getCallStackMod() {
|
|
||||||
return defaultModel.getExtrapop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getCallStackShift() {
|
|
||||||
return defaultModel.getStackshift();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PrototypeModel[] getCallingConventions() {
|
public PrototypeModel[] getCallingConventions() {
|
||||||
return models;
|
return models;
|
||||||
|
|
|
@ -89,22 +89,6 @@ public interface CompilerSpec {
|
||||||
*/
|
*/
|
||||||
public AddressSpace getStackBaseSpace();
|
public AddressSpace getStackBaseSpace();
|
||||||
|
|
||||||
/**
|
|
||||||
* Number of extra bytes popped from the stack on return
|
|
||||||
* -1 if it is unknown.
|
|
||||||
* @return # of bytes popped from the stack by a called function on return.
|
|
||||||
*/
|
|
||||||
public int getCallStackMod();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the normal shift in the stack at the call to this routine.
|
|
||||||
* This will be the things pushed on the stack as part of the calling
|
|
||||||
* conventions. Normally the return value.
|
|
||||||
*
|
|
||||||
* @return entry stack shift or -1 if it is unknown
|
|
||||||
*/
|
|
||||||
public int getCallStackShift();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if stack grows with negative offsets
|
* Returns true if stack grows with negative offsets
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -112,16 +112,17 @@ public class FunctionPrototype {
|
||||||
// function pointer, in which case forcing the void
|
// function pointer, in which case forcing the void
|
||||||
// causes the decompiler to drop real parameters.
|
// causes the decompiler to drop real parameters.
|
||||||
// At the moment, we turn on varargs if there are no params
|
// At the moment, we turn on varargs if there are no params
|
||||||
if (voidimpliesdotdotdot && voidinputlock)
|
if (voidimpliesdotdotdot && voidinputlock) {
|
||||||
dotdotdot = true;
|
dotdotdot = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populate Function Prototype from information attached to a function in the Program DB.
|
* Populate Function Prototype from information attached to a function in the Program DB.
|
||||||
*
|
*
|
||||||
* @param f is the function to grab prototype from
|
* @param f is the function to grab prototype from
|
||||||
* @param default_extrapop
|
* @param default_extrapop is the default extrapop to use if the function's is unknown
|
||||||
* @param override_extrapop
|
* @param override_extrapop is true if the extrapop should be overridden
|
||||||
*/
|
*/
|
||||||
void grabFromFunction(Function f, int default_extrapop, boolean override_extrapop) {
|
void grabFromFunction(Function f, int default_extrapop, boolean override_extrapop) {
|
||||||
modelname = f.getCallingConventionName();
|
modelname = f.getCallingConventionName();
|
||||||
|
@ -134,10 +135,12 @@ public class FunctionPrototype {
|
||||||
returnstorage = returnparam.getVariableStorage();
|
returnstorage = returnparam.getVariableStorage();
|
||||||
|
|
||||||
SourceType sigSource = f.getSignatureSource();
|
SourceType sigSource = f.getSignatureSource();
|
||||||
if (sigSource != SourceType.DEFAULT)
|
if (sigSource != SourceType.DEFAULT) {
|
||||||
outputlock = DataType.DEFAULT != returntype;
|
outputlock = DataType.DEFAULT != returntype;
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
outputlock = false;
|
outputlock = false;
|
||||||
|
}
|
||||||
|
|
||||||
if ((returnstorage == null) || (!returnstorage.isValid())) { // Unassigned or otherwise invalid storage
|
if ((returnstorage == null) || (!returnstorage.isValid())) { // Unassigned or otherwise invalid storage
|
||||||
outputlock = false;
|
outputlock = false;
|
||||||
|
@ -162,7 +165,11 @@ public class FunctionPrototype {
|
||||||
extrapop = default_extrapop;
|
extrapop = default_extrapop;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
extrapop = purge + f.getProgram().getCompilerSpec().getCallStackShift();
|
PrototypeModel protoModel = f.getCallingConvention();
|
||||||
|
if (protoModel == null) {
|
||||||
|
protoModel = f.getProgram().getCompilerSpec().getDefaultCallingConvention();
|
||||||
|
}
|
||||||
|
extrapop = purge + protoModel.getStackshift();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,8 +194,9 @@ public class FunctionPrototype {
|
||||||
* @return the number of defined parameters for this function prototype
|
* @return the number of defined parameters for this function prototype
|
||||||
*/
|
*/
|
||||||
public int getNumParams() {
|
public int getNumParams() {
|
||||||
if (localsyms != null)
|
if (localsyms != null) {
|
||||||
return localsyms.getNumParams();
|
return localsyms.getNumParams();
|
||||||
|
}
|
||||||
return params.length;
|
return params.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,8 +206,9 @@ public class FunctionPrototype {
|
||||||
* if this prototype is not backed by a LocalSymbolMap
|
* if this prototype is not backed by a LocalSymbolMap
|
||||||
*/
|
*/
|
||||||
public HighParam getParam(int i) {
|
public HighParam getParam(int i) {
|
||||||
if (localsyms != null)
|
if (localsyms != null) {
|
||||||
return localsyms.getParam(i);
|
return localsyms.getParam(i);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,36 +308,50 @@ public class FunctionPrototype {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* append an XML string representing this function prototype
|
* append an XML string representing this function prototype
|
||||||
|
* @param res is where the string should be appended
|
||||||
|
* @param dtmanage is the DataTypeManager for building type reference tags
|
||||||
*/
|
*/
|
||||||
public void buildPrototypeXML(StringBuilder res, PcodeDataTypeManager dtmanage) {
|
public void buildPrototypeXML(StringBuilder res, PcodeDataTypeManager dtmanage) {
|
||||||
res.append("<prototype");
|
res.append("<prototype");
|
||||||
if (extrapop == PrototypeModel.UNKNOWN_EXTRAPOP)
|
if (extrapop == PrototypeModel.UNKNOWN_EXTRAPOP) {
|
||||||
SpecXmlUtils.encodeStringAttribute(res, "extrapop", "unknown");
|
SpecXmlUtils.encodeStringAttribute(res, "extrapop", "unknown");
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
SpecXmlUtils.encodeSignedIntegerAttribute(res, "extrapop", extrapop);
|
SpecXmlUtils.encodeSignedIntegerAttribute(res, "extrapop", extrapop);
|
||||||
|
}
|
||||||
SpecXmlUtils.encodeStringAttribute(res, "model", modelname);
|
SpecXmlUtils.encodeStringAttribute(res, "model", modelname);
|
||||||
if (modellock)
|
if (modellock) {
|
||||||
SpecXmlUtils.encodeBooleanAttribute(res, "modellock", modellock);
|
SpecXmlUtils.encodeBooleanAttribute(res, "modellock", modellock);
|
||||||
if (dotdotdot)
|
}
|
||||||
|
if (dotdotdot) {
|
||||||
SpecXmlUtils.encodeBooleanAttribute(res, "dotdotdot", dotdotdot);
|
SpecXmlUtils.encodeBooleanAttribute(res, "dotdotdot", dotdotdot);
|
||||||
if (voidinputlock)
|
}
|
||||||
|
if (voidinputlock) {
|
||||||
SpecXmlUtils.encodeBooleanAttribute(res, "voidlock", voidinputlock);
|
SpecXmlUtils.encodeBooleanAttribute(res, "voidlock", voidinputlock);
|
||||||
if (isinline)
|
}
|
||||||
|
if (isinline) {
|
||||||
SpecXmlUtils.encodeBooleanAttribute(res, "inline", isinline);
|
SpecXmlUtils.encodeBooleanAttribute(res, "inline", isinline);
|
||||||
if (noreturn)
|
}
|
||||||
|
if (noreturn) {
|
||||||
SpecXmlUtils.encodeBooleanAttribute(res, "noreturn", noreturn);
|
SpecXmlUtils.encodeBooleanAttribute(res, "noreturn", noreturn);
|
||||||
if (custom)
|
}
|
||||||
|
if (custom) {
|
||||||
SpecXmlUtils.encodeBooleanAttribute(res, "custom", custom);
|
SpecXmlUtils.encodeBooleanAttribute(res, "custom", custom);
|
||||||
if (hasThis)
|
}
|
||||||
|
if (hasThis) {
|
||||||
SpecXmlUtils.encodeBooleanAttribute(res, "hasthis", hasThis);
|
SpecXmlUtils.encodeBooleanAttribute(res, "hasthis", hasThis);
|
||||||
if (isConstruct)
|
}
|
||||||
|
if (isConstruct) {
|
||||||
SpecXmlUtils.encodeBooleanAttribute(res, "constructor", isConstruct);
|
SpecXmlUtils.encodeBooleanAttribute(res, "constructor", isConstruct);
|
||||||
if (isDestruct)
|
}
|
||||||
|
if (isDestruct) {
|
||||||
SpecXmlUtils.encodeBooleanAttribute(res, "destructor", isDestruct);
|
SpecXmlUtils.encodeBooleanAttribute(res, "destructor", isDestruct);
|
||||||
|
}
|
||||||
res.append(">\n");
|
res.append(">\n");
|
||||||
res.append(" <returnsym");
|
res.append(" <returnsym");
|
||||||
if (outputlock)
|
if (outputlock) {
|
||||||
SpecXmlUtils.encodeBooleanAttribute(res, "typelock", outputlock);
|
SpecXmlUtils.encodeBooleanAttribute(res, "typelock", outputlock);
|
||||||
|
}
|
||||||
res.append(">\n ");
|
res.append(">\n ");
|
||||||
int sz = returntype.getLength();
|
int sz = returntype.getLength();
|
||||||
if (sz < 0) {
|
if (sz < 0) {
|
||||||
|
@ -338,14 +361,16 @@ public class FunctionPrototype {
|
||||||
if ((returnstorage != null) && returnstorage.isValid() &&
|
if ((returnstorage != null) && returnstorage.isValid() &&
|
||||||
(!returnstorage.isVoidStorage())) {
|
(!returnstorage.isVoidStorage())) {
|
||||||
int logicalsize = 0; // Assume logicalsize of return matches datatype size
|
int logicalsize = 0; // Assume logicalsize of return matches datatype size
|
||||||
if (sz != returnstorage.size()) // If the sizes do not match
|
if (sz != returnstorage.size()) { // If the sizes do no match
|
||||||
logicalsize = sz; // force the logical size on the varnode
|
logicalsize = sz; // force the logical size on the varnode
|
||||||
|
}
|
||||||
String addrstring = Varnode.buildXMLAddress(returnstorage.getVarnodes(), logicalsize);
|
String addrstring = Varnode.buildXMLAddress(returnstorage.getVarnodes(), logicalsize);
|
||||||
res.append(addrstring).append("\n ");
|
res.append(addrstring).append("\n ");
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
// Decompiler will use model for storage
|
// Decompiler will use model for storage
|
||||||
res.append("<addr/>\n "); // Don't specify where return type is stored
|
res.append("<addr/>\n "); // Don't specify where return type is stored
|
||||||
|
}
|
||||||
|
|
||||||
res.append(dtmanage.buildTypeRef(returntype, sz));
|
res.append(dtmanage.buildTypeRef(returntype, sz));
|
||||||
res.append(" </returnsym>\n");
|
res.append(" </returnsym>\n");
|
||||||
|
@ -370,8 +395,9 @@ public class FunctionPrototype {
|
||||||
res.append("\">\n");
|
res.append("\">\n");
|
||||||
res.append(" <addr/>\n "); // Blank address
|
res.append(" <addr/>\n "); // Blank address
|
||||||
sz = dt.getLength();
|
sz = dt.getLength();
|
||||||
if (sz < 0)
|
if (sz < 0) {
|
||||||
sz = 1;
|
sz = 1;
|
||||||
|
}
|
||||||
res.append(dtmanage.buildTypeRef(dt, sz));
|
res.append(dtmanage.buildTypeRef(dt, sz));
|
||||||
res.append("</param>\n");
|
res.append("</param>\n");
|
||||||
}
|
}
|
||||||
|
@ -381,21 +407,22 @@ public class FunctionPrototype {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the function prototype from an XML tree node.
|
* Parse the function prototype from <prototype> tag.
|
||||||
*
|
* @param parser is the XML document to parse
|
||||||
* @param node XML tree node from a parsing of a larger XML document
|
* @param dtmanage is the DataTypeManager used to parse data-type tags
|
||||||
*
|
* @throws PcodeXMLException for any problems parsing
|
||||||
* @throws PcodeXMLException
|
|
||||||
*/
|
*/
|
||||||
public void readPrototypeXML(XmlPullParser parser, PcodeDataTypeManager dtmanage)
|
public void readPrototypeXML(XmlPullParser parser, PcodeDataTypeManager dtmanage)
|
||||||
throws PcodeXMLException {
|
throws PcodeXMLException {
|
||||||
XmlElement node = parser.start("prototype");
|
XmlElement node = parser.start("prototype");
|
||||||
modelname = node.getAttribute("model");
|
modelname = node.getAttribute("model");
|
||||||
String val = node.getAttribute("extrapop");
|
String val = node.getAttribute("extrapop");
|
||||||
if (val.equals("unknown"))
|
if (val.equals("unknown")) {
|
||||||
extrapop = PrototypeModel.UNKNOWN_EXTRAPOP;
|
extrapop = PrototypeModel.UNKNOWN_EXTRAPOP;
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
extrapop = SpecXmlUtils.decodeInt(val);
|
extrapop = SpecXmlUtils.decodeInt(val);
|
||||||
|
}
|
||||||
modellock = false;
|
modellock = false;
|
||||||
if (node.hasAttribute("modellock")) {
|
if (node.hasAttribute("modellock")) {
|
||||||
modellock = SpecXmlUtils.decodeBoolean(node.getAttribute("modellock"));
|
modellock = SpecXmlUtils.decodeBoolean(node.getAttribute("modellock"));
|
||||||
|
@ -434,16 +461,18 @@ public class FunctionPrototype {
|
||||||
}
|
}
|
||||||
XmlElement retel = parser.start("returnsym");
|
XmlElement retel = parser.start("returnsym");
|
||||||
outputlock = false;
|
outputlock = false;
|
||||||
if (retel.hasAttribute("typelock"))
|
if (retel.hasAttribute("typelock")) {
|
||||||
outputlock = SpecXmlUtils.decodeBoolean(retel.getAttribute("typelock"));
|
outputlock = SpecXmlUtils.decodeBoolean(retel.getAttribute("typelock"));
|
||||||
|
}
|
||||||
parser.discardSubTree();
|
parser.discardSubTree();
|
||||||
returnstorage = null; // For now don't use decompiler's return storage
|
returnstorage = null; // For now don't use decompiler's return storage
|
||||||
returntype = dtmanage.readXMLDataType(parser);
|
returntype = dtmanage.readXMLDataType(parser);
|
||||||
parser.end(retel);
|
parser.end(retel);
|
||||||
|
|
||||||
XmlElement peeknode = parser.peek();
|
XmlElement peeknode = parser.peek();
|
||||||
if ((peeknode != null) && peeknode.isStart())
|
if ((peeknode != null) && peeknode.isStart()) {
|
||||||
parser.discardSubTree(); // The decompiler may return an <inject> tag
|
parser.discardSubTree(); // The decompiler may return an <inject> tag
|
||||||
|
}
|
||||||
parser.end(node);
|
parser.end(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -539,16 +539,6 @@ class TemporaryCompilerSpec implements CompilerSpec {
|
||||||
public void applyContextSettings(DefaultProgramContext ctx) {
|
public void applyContextSettings(DefaultProgramContext ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getCallStackMod() {
|
|
||||||
return newCompilerSpec.getCallStackMod();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getCallStackShift() {
|
|
||||||
return newCompilerSpec.getCallStackShift();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PrototypeModel[] getCallingConventions() {
|
public PrototypeModel[] getCallingConventions() {
|
||||||
return new PrototypeModel[0];
|
return new PrototypeModel[0];
|
||||||
|
|
|
@ -85,7 +85,7 @@
|
||||||
<register name="DF"/>
|
<register name="DF"/>
|
||||||
</unaffected>
|
</unaffected>
|
||||||
</prototype>
|
</prototype>
|
||||||
<prototype name="__stdcall16far" extrapop="unknown" stackshift="2">
|
<prototype name="__stdcall16far" extrapop="unknown" stackshift="4">
|
||||||
<input>
|
<input>
|
||||||
<pentry minsize="1" maxsize="500" align="2">
|
<pentry minsize="1" maxsize="500" align="2">
|
||||||
<addr offset="4" space="stack"/>
|
<addr offset="4" space="stack"/>
|
||||||
|
@ -111,7 +111,7 @@
|
||||||
<register name="DF"/>
|
<register name="DF"/>
|
||||||
</unaffected>
|
</unaffected>
|
||||||
</prototype>
|
</prototype>
|
||||||
<prototype name="__cdecl16far" extrapop="4" stackshift="2">
|
<prototype name="__cdecl16far" extrapop="4" stackshift="4">
|
||||||
<input>
|
<input>
|
||||||
<pentry minsize="1" maxsize="500" align="2">
|
<pentry minsize="1" maxsize="500" align="2">
|
||||||
<addr offset="4" space="stack"/>
|
<addr offset="4" space="stack"/>
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
<data>0x4dcb</data> <!-- DEC(BP) RET() -->
|
<data>0x4dcb</data> <!-- DEC(BP) RET() -->
|
||||||
<data>0.011... 1100.011</data> <!-- POP(BP|BX|DS|SI) RET -->
|
<data>0.011... 1100.011</data> <!-- POP(BP|BX|DS|SI) RET -->
|
||||||
<data>1100.010 .0.....0 0x00</data> <!-- RET(constant) -->
|
<data>1100.010 .0.....0 0x00</data> <!-- RET(constant) -->
|
||||||
<data>0xc390</data> <!-- RET NOP -->
|
<data>1100.010 .0.....0 0x00 0x90</data> <!-- RET(constant) NOP -->
|
||||||
|
<data>0xc390</data> <!-- RET NOP -->
|
||||||
<data>0xcb90</data>
|
<data>0xcb90</data>
|
||||||
<data>0xc3</data>
|
<data>0xc3</data>
|
||||||
</prepatterns>
|
</prepatterns>
|
||||||
|
@ -15,6 +16,7 @@
|
||||||
<data>0x5589e5</data> <!-- PUSH(BP) MOV(BP,SP) -->
|
<data>0x5589e5</data> <!-- PUSH(BP) MOV(BP,SP) -->
|
||||||
<data>0xc8 000....0 0x0000</data> <!-- ENTER (constant, 0x0) -->
|
<data>0xc8 000....0 0x0000</data> <!-- ENTER (constant, 0x0) -->
|
||||||
<data>0x8cd89045</data> <!-- MOV(AX,DS) NOP INC(BP) -->
|
<data>0x8cd89045</data> <!-- MOV(AX,DS) NOP INC(BP) -->
|
||||||
|
<data>0x8cd055</data> <!-- MOV(AX,SS) PUSH(BP) -->
|
||||||
<funcstart/>
|
<funcstart/>
|
||||||
</postpatterns>
|
</postpatterns>
|
||||||
</patternpairs>
|
</patternpairs>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue