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 eb42edc861..4e4436eea3 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 @@ -273,8 +273,7 @@ public class CallDepthChangeInfo { PcodeOp[] pcode = instr.getPcode(); Varnode outVarNode = null; - for (int i = 0; i < pcode.length; i++) { - PcodeOp op = pcode[i]; + for (PcodeOp op : pcode) { Varnode input0 = op.getInput(0); Varnode input1 = op.getInput(1); Varnode output = op.getOutput(); @@ -317,9 +316,10 @@ public class CallDepthChangeInfo { break; case PcodeOp.INT_AND: // Assume this is a stack alignment and do the and if (isStackPointer(input0)) { - if (currentStackDepth != Function.UNKNOWN_STACK_DEPTH_CHANGE) + if (currentStackDepth != Function.UNKNOWN_STACK_DEPTH_CHANGE) { possibleDepthChange = (int) (currentStackDepth & input1.getOffset()) - currentStackDepth; + } outVarNode = output; } else if (input0.equals(outVarNode)) { @@ -327,9 +327,10 @@ public class CallDepthChangeInfo { outVarNode = output; } else if (isStackPointer(input1)) { - if (currentStackDepth != Function.UNKNOWN_STACK_DEPTH_CHANGE) + if (currentStackDepth != Function.UNKNOWN_STACK_DEPTH_CHANGE) { possibleDepthChange = (int) (currentStackDepth & input0.getOffset()) - currentStackDepth; + } outVarNode = output; } else if (input1.equals(outVarNode)) { @@ -385,7 +386,7 @@ public class CallDepthChangeInfo { // TODO: Modify return by normal stack shift.... 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. @@ -419,8 +420,9 @@ public class CallDepthChangeInfo { * @return */ private int getDefaultStackDepthChange(int depth) { - int callStackMod = program.getCompilerSpec().getCallStackMod(); - int callStackShift = program.getCompilerSpec().getCallStackShift(); + PrototypeModel defaultModel = program.getCompilerSpec().getDefaultCallingConvention(); + int callStackMod = defaultModel.getExtrapop(); + int callStackShift = defaultModel.getStackshift(); if (callStackMod != PrototypeModel.UNKNOWN_EXTRAPOP && callStackShift >= 0) { return callStackShift - callStackMod; } @@ -578,8 +580,8 @@ public class CallDepthChangeInfo { FlowType flow = instr.getFlowType(); if (!flow.isCall()) { Address[] flows = instr.getFlows(); - for (int i = 0; i < flows.length; i++) { - st.push(flows[i]); + for (Address flow2 : flows) { + st.push(flow2); st.push(new Integer(stackPointerDepth)); st.push(stackOK); } @@ -653,7 +655,7 @@ public class CallDepthChangeInfo { return; } - int purge = (short) program.getCompilerSpec().getCallStackMod(); + int purge = (short) program.getCompilerSpec().getDefaultCallingConvention().getExtrapop(); final boolean possiblePurge = purge == -1 || purge > 3200 || purge < -3200; // follow all flows building up context @@ -948,8 +950,8 @@ public class CallDepthChangeInfo { FlowType flow = instr.getFlowType(); if (!flow.isCall()) { Address[] flows = instr.getFlows(); - for (int i = 0; i < flows.length; i++) { - st.push(flows[i]); + for (Address flow2 : flows) { + st.push(flow2); st.push(new Integer(stackPointerDepth)); st.push(stackOK); } @@ -1027,11 +1029,11 @@ public class CallDepthChangeInfo { } // try to find a call destination that the stack frame is known - for (int i = 0; i < flows.length; i++) { - if (flows[i] == null) { + for (Address flow : flows) { + if (flow == null) { continue; } - Function func = program.getListing().getFunctionAt(flows[i]); + Function func = program.getListing().getFunctionAt(flow); if (func != null) { int purge = func.getStackPurgeSize(); if (func.isStackPurgeSizeValid() && purge != Function.UNKNOWN_STACK_DEPTH_CHANGE && diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionPurgeAnalysisCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionPurgeAnalysisCmd.java index 605a427fcd..58bb7a2ba7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionPurgeAnalysisCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionPurgeAnalysisCmd.java @@ -17,15 +17,16 @@ package ghidra.app.cmd.function; import ghidra.framework.cmd.BackgroundCommand; import ghidra.framework.model.DomainObject; -import ghidra.program.model.address.AddressSet; -import ghidra.program.model.address.AddressSetView; +import ghidra.program.model.address.*; import ghidra.program.model.lang.Processor; +import ghidra.program.model.lang.PrototypeModel; import ghidra.program.model.listing.*; +import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.scalar.Scalar; -import ghidra.program.model.symbol.FlowType; -import ghidra.program.model.symbol.Reference; +import ghidra.program.model.symbol.*; import ghidra.util.Msg; import ghidra.util.exception.CancelledException; +import ghidra.util.exception.InvalidInputException; import ghidra.util.task.TaskMonitor; /** @@ -34,13 +35,17 @@ import ghidra.util.task.TaskMonitor; public class FunctionPurgeAnalysisCmd extends BackgroundCommand { private AddressSetView entryPoints; 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. * @param entries and address set indicating the entry points of functions that have * 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) { super("Compute Function Purge", true, true, false); @@ -56,12 +61,16 @@ public class FunctionPurgeAnalysisCmd extends BackgroundCommand { program = (Program) obj; 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"))) { Msg.error(this, "Unsupported operation for language " + program.getLanguage().getLanguageID()); return false; } + if (defaultSpace instanceof SegmentedAddressSpace) { // For 16-bit x86, prepare to establish near/fear calling convention models + setupNearFarModels(); + } AddressSetView set = entryPoints; @@ -95,6 +104,52 @@ public class FunctionPurgeAnalysisCmd extends BackgroundCommand { 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. * @param function function to be analyzed @@ -104,39 +159,120 @@ public class FunctionPurgeAnalysisCmd extends BackgroundCommand { */ private void analyzeFunction(Function function, TaskMonitor monitor) throws CancelledException { - int purge = -1; - - if (function != null) { - purge = function.getStackPurgeSize(); + if (function == null) { + return; } + int purge = function.getStackPurgeSize(); if (purge == -1 || purge > 128 || purge < -128) { - purge = locatePurgeReturn(program, function, monitor); - // if couldn't find it, don't set it! - if (purge != -1) { - function.setStackPurgeSize(purge); + Instruction purgeInstruction = locatePurgeInstruction(function, monitor); + if (purgeInstruction != null) { + purge = getPurgeValue(purgeInstruction); + // 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) { - AddressSetView body = func.getBody(); + private void setPrototypeModel(Function function, Instruction purgeInstruction) { + 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); - if (returnPurge != -1) { - return returnPurge; + private Instruction locatePurgeInstruction(Function func, TaskMonitor monitor) { + AddressSetView body = func.getBody(); + Instruction purgeInstruction; + + purgeInstruction = findPurgeInstruction(body); + if (purgeInstruction != null) { + return purgeInstruction; } // look harder, maybe something wrong with body, compute with flow. body = CreateFunctionCmd.getFunctionBody(program, func.getEntryPoint(), monitor); - returnPurge = findReturnPurge(program, body); - - return returnPurge; + return findPurgeInstruction(body); } - 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); int count = 2048; + Instruction backupPurge = null; while (iter.hasNext() && count > 0) { count--; Instruction instr = iter.next(); @@ -144,33 +280,15 @@ public class FunctionPurgeAnalysisCmd extends BackgroundCommand { FlowType ftype = instr.getFlowType(); if (ftype.isTerminal()) { if (instr.getMnemonicString().compareToIgnoreCase("ret") == 0) { - tempPurge = 0; - Scalar scalar = instr.getScalar(0); - if (scalar != null) { - tempPurge = (int) scalar.getSignedValue(); - return tempPurge; - } - return 0; + return instr; } else if (ftype.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(); - } - } - } + backupPurge = instr; // Use as last resort, if we can't find RET } } } - return -1; + return backupPurge; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionResultStateStackAnalysisCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionResultStateStackAnalysisCmd.java index 73e998a5b5..045fe5f9a3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionResultStateStackAnalysisCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionResultStateStackAnalysisCmd.java @@ -169,8 +169,9 @@ public class FunctionResultStateStackAnalysisCmd extends BackgroundCommand { // Process all the functions identified as needing stack analysis. // The list will have the lowest level functions analyzed first. - int default_extraPop = program.getCompilerSpec().getCallStackMod(); - int default_stackshift = program.getCompilerSpec().getCallStackShift(); + PrototypeModel defaultModel = program.getCompilerSpec().getDefaultCallingConvention(); + int default_extraPop = defaultModel.getExtrapop(); + int default_stackshift = defaultModel.getStackshift(); while (!funcList.isEmpty()) { monitor.checkCanceled(); @@ -256,19 +257,22 @@ public class FunctionResultStateStackAnalysisCmd extends BackgroundCommand { int storageSpaceID, RefType refType, TaskMonitor monitor1) throws CancelledException { - if (instrOpIndex < 0) + if (instrOpIndex < 0) { return; + } Address fromAddr = op.getSeqnum().getTarget(); Instruction instr = listing.getInstructionAt(fromAddr); - if (instr == null) + if (instr == null) { return; + } Address stackAddr = addrFactory.getStackSpace().getAddress(stackOffset); RefType rt = refType; Reference ref = refMgr.getReference(fromAddr, stackAddr, instrOpIndex); if (ref != null) { RefType existingRefType = ref.getReferenceType(); - if (existingRefType == rt) + if (existingRefType == rt) { return; + } if (existingRefType == RefType.READ || existingRefType == RefType.WRITE) { rt = RefType.READ_WRITE; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractLibrarySupportLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractLibrarySupportLoader.java index 4dbf12095e..7a62948957 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractLibrarySupportLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractLibrarySupportLoader.java @@ -892,14 +892,14 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader if (expSym.hasNoReturn()) { extFunc.setNoReturn(true); } - int stackShift = program.getCompilerSpec().getCallStackShift(); - 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 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; // if (numParams > 0) { // // HACK: assumes specific stack-based x86 convention diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java index 172bf0f20f..39157d281d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java @@ -1705,8 +1705,9 @@ public class SymbolicPropogator { * @return */ private int getDefaultStackDepthChange(Program prog, int depth) { - int callStackMod = prog.getCompilerSpec().getCallStackMod(); - int callStackShift = prog.getCompilerSpec().getCallStackShift(); + PrototypeModel defaultModel = prog.getCompilerSpec().getDefaultCallingConvention(); + int callStackMod = defaultModel.getExtrapop(); + int callStackShift = defaultModel.getStackshift(); if (callStackMod != PrototypeModel.UNKNOWN_EXTRAPOP) { return callStackShift; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/state/ResultsState.java b/Ghidra/Features/Base/src/main/java/ghidra/util/state/ResultsState.java index 999f4042c1..257d4855b8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/util/state/ResultsState.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/util/state/ResultsState.java @@ -46,14 +46,17 @@ public class ResultsState { private static final Iterator emptyContextStateIterator = new Iterator() { + @Override public boolean hasNext() { return false; } + @Override public ContextState next() { return null; } + @Override public void remove() { } }; @@ -168,10 +171,12 @@ public class ResultsState { stackGrowsNegative = program.getCompilerSpec().stackGrowsNegative(); Long stackOffset = currentPrototype.getStackParameterOffset(); - if (stackOffset != null) + if (stackOffset != null) { paramBaseStackOffset = stackOffset - currentPrototype.getStackshift(); - else + } + else { paramBaseStackOffset = null; + } todoList.add(new BranchDestination(null, entryPt, entryState)); } @@ -253,9 +258,10 @@ public class ResultsState { currentState = null; } - if (DEBUG) + if (DEBUG) { Msg.debug(this, ">>> At " + nextSeq.getTarget() + "/" + nextSeq.getTime() + " " + instr); + } SequenceNumber lastSeq = flowFrom; @@ -272,9 +278,10 @@ public class ResultsState { if (existingStates.containsKey(flowFrom)) { // TODO: We have processed this flow before // TODO: Should we compare existingState with dest.initialState ? - if (DEBUG) + if (DEBUG) { Msg.debug(this, "Flow ignored - already processed: " + flowFrom + " -> " + pcodeOp.getSeqnum()); + } instr = null; // signal - abort current flow break; } @@ -284,9 +291,10 @@ public class ResultsState { // Re-use existing state where register values match addState(flowFrom, otherEntryState); instr = null; // signal - abort current flow - if (DEBUG) + if (DEBUG) { Msg.debug(this, "Flow combined - similar state: " + flowFrom + " -> " + pcodeOp.getSeqnum()); + } break; } } @@ -385,6 +393,7 @@ public class ResultsState { private static Comparator CONTEXT_STATE_SET_SEQUENCE_COMPARATOR = new Comparator() { + @Override public int compare(Object o1, Object o2) { ContextStateSet set = (ContextStateSet) o1; SequenceNumber seq = (SequenceNumber) o2; @@ -468,14 +477,16 @@ public class ResultsState { private ContextState performInlineCall(Address inlineCallAddress, ContextState currentState, TaskMonitor monitor) throws CancelledException { - if (DEBUG) + if (DEBUG) { Msg.debug(this, "*** Start Inline Call to " + inlineCallAddress + " ***"); + } ResultsState inlineState = new ResultsState(new SequenceNumber(inlineCallAddress, 0), null, currentState, maintainInstructionResults); inlineState.processFunction(monitor); - if (DEBUG) + if (DEBUG) { Msg.debug(this, "*** End Inline Call to " + inlineCallAddress + " ***"); + } // TODO: How should multiple return states be handled ?? @@ -746,9 +757,10 @@ public class ResultsState { if (values[1].isConstant() && values[1].getOffset() == 0) { // 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() + " - Not taken due to false condition value"); + } break; // Fall-through case - assume that a pre-condition is steering the execution } @@ -762,16 +774,18 @@ public class ResultsState { SequenceNumber dest = new SequenceNumber(seq.getTarget(), seq.getTime() + (int) inputs[0].getOffset()); - if (DEBUG) + if (DEBUG) { Msg.debug(this, "Internal " + (pcodeOp.getOpcode() == PcodeOp.CBRANCH ? "Conditional " : "") + "Branch to " + dest); + } todoList.add(new BranchDestination(pcodeOp.getSeqnum(), dest, currentState)); } else if (inputs[0].isAddress()) { - if (DEBUG) + if (DEBUG) { Msg.debug(this, (pcodeOp.getOpcode() == PcodeOp.CBRANCH ? "Conditional " : "") + "Branch to " + inputs[0].getAddress()); + } handleDirectFlow(pcodeOp, inputs[0].getAddress(), currentState, monitor); } else { @@ -786,8 +800,9 @@ public class ResultsState { AddressSpace space = currentState.getEntryPoint().getTarget().getAddressSpace(); Address destAddr = space.getAddress(getUnsignedOffset(values[0], space.getPointerSize())); - if (DEBUG) + if (DEBUG) { Msg.debug(this, "Branch to " + destAddr); + } handleDirectFlow(pcodeOp, destAddr, currentState, monitor); } else if (values[0].isAddress()) { @@ -798,32 +813,36 @@ public class ResultsState { currentState.getEntryPoint().getTarget().getAddressSpace(); Address destAddr = space.getAddress(getUnsignedOffset(brOffset, space.getPointerSize())); - if (DEBUG) + if (DEBUG) { Msg.debug(this, "Indirect Branch to [" + values[0].getAddress() + "] -> " + destAddr); + } handleDirectFlow(pcodeOp, destAddr, currentState, monitor); } else { - if (DEBUG) + if (DEBUG) { Msg.debug(this, "Indirect Branch to [" + values[0].toString(program.getLanguage()) + "]"); + } handleIndirectFlow(pcodeOp, values[0], currentState, monitor); } } else { - if (DEBUG) + if (DEBUG) { Msg.debug(this, "Indirect Branch to [" + values[0].toString(program.getLanguage()) + "]"); + } handleIndirectFlow(pcodeOp, values[0], currentState, monitor); } return false; case PcodeOp.CALL: // A call with absolute address if (inputs[0].isAddress()) { - if (DEBUG) + if (DEBUG) { Msg.debug(this, "Call to " + inputs[0].getAddress()); + } handleCall(pcodeOp, null, inputs[0].getAddress(), currentState, monitor); } else { @@ -839,8 +858,9 @@ public class ResultsState { AddressSpace space = currentState.getEntryPoint().getTarget().getAddressSpace(); Address destAddr = space.getAddress(getUnsignedOffset(values[0], space.getPointerSize())); - if (DEBUG) + if (DEBUG) { Msg.debug(this, "Call to " + destAddr); + } handleCall(pcodeOp, indirectPtr, destAddr, currentState, monitor); } else if (values[0].isAddress()) { @@ -852,23 +872,26 @@ public class ResultsState { currentState.getEntryPoint().getTarget().getAddressSpace(); Address destAddr = space.getAddress(getUnsignedOffset(callOffset, space.getPointerSize())); - if (DEBUG) + if (DEBUG) { Msg.debug(this, "Indirect Call to [" + values[0].getAddress() + "] -> " + destAddr); + } handleCall(pcodeOp, indirectPtr, destAddr, currentState, monitor); } else { - if (DEBUG) + if (DEBUG) { Msg.debug(this, "Indirect Call to [" + values[0].toString(program.getLanguage()) + "]"); + } handleIndirectCall(pcodeOp, indirectPtr, values[0], currentState, monitor); } } else { - if (DEBUG) + if (DEBUG) { Msg.debug(this, "Indirect Call to [" + values[0].toString(program.getLanguage()) + "]"); + } handleIndirectCall(pcodeOp, indirectPtr, values[0], currentState, monitor); } return false; @@ -1737,8 +1760,9 @@ public class ResultsState { BookmarkType.ERROR, "Instruction Expected", "Expected instruction at " + address); return; } - if (DEBUG) + if (DEBUG) { Msg.debug(this, "Disassemble at " + address); + } DisassembleCommand cmd = new DisassembleCommand(address, null, true); cmd.applyTo(program, monitor); monitor.checkCanceled(); @@ -1772,8 +1796,9 @@ public class ResultsState { return; } if (addRegister(reg, registersModified)) { - if (DEBUG) + if (DEBUG) { Msg.debug(this, "MODIFIED: " + reg + " = " + value); + } } else { Msg.debug(this, "SET: " + output + " = " + value); @@ -2068,10 +2093,11 @@ public class ResultsState { } if (func == null) { - if (DEBUG) + if (DEBUG) { Msg.debug(this, "Function not found at " + indirectPtr + " indirectly called from " + pcodeOp.getSeqnum().getTarget() + " - call affects unknown"); + } return; } @@ -2104,9 +2130,10 @@ public class ResultsState { } if (func == null) { - if (DEBUG) + if (DEBUG) { Msg.debug(this, "Function not found at " + destAddr + " called from " + pcodeOp.getSeqnum().getTarget() + " - call affects unknown"); + } return; } @@ -2133,10 +2160,11 @@ public class ResultsState { // Must invalidate return varnode DataType returnType = null; if (func == null) { - if (DEBUG) + if (DEBUG) { Msg.debug(this, "No function at " + destAddr + " called from " + calledFrom.getTarget() + " - default return/affects assumed"); + } } else { returnType = func.getReturnType(); @@ -2147,8 +2175,9 @@ public class ResultsState { VariableStorage retStorage = callingConvention.getReturnLocation(returnType, program); Varnode varnode = null; - if (retStorage.isValid() && (retStorage.getVarnodeCount()==1)) + if (retStorage.isValid() && (retStorage.getVarnodeCount()==1)) { varnode = retStorage.getFirstVarnode(); + } if (varnode != null) { // invalidate stored value currentState.store(varnode, getInvalidatedVarnode(calledFrom, varnode)); @@ -2183,9 +2212,10 @@ public class ResultsState { if (purge == Function.UNKNOWN_STACK_DEPTH_CHANGE || purge == Function.INVALID_STACK_DEPTH_CHANGE) { String name = func != null ? func.getName() : ("at " + destAddr); - if (DEBUG) + if (DEBUG) { Msg.debug(this, "Stack purge unknown for function " + name + " called from " + calledFrom.getTarget() + " - stack pointer invalidated"); + } currentState.store(getStackPointerVarnode(), getInvalidatedVarnode(calledFrom, getStackPointerVarnode())); return; @@ -2255,8 +2285,9 @@ public class ResultsState { * @return */ private static int getDefaultStackDepthChange(Program depthProgram, int depth) { - int callStackMod = depthProgram.getCompilerSpec().getCallStackMod(); - int callStackShift = depthProgram.getCompilerSpec().getCallStackShift(); + PrototypeModel defaultModel = depthProgram.getCompilerSpec().getDefaultCallingConvention(); + int callStackMod = defaultModel.getExtrapop(); + int callStackShift = defaultModel.getStackshift(); if (callStackMod != PrototypeModel.UNKNOWN_EXTRAPOP && callStackShift >= 0) { return callStackShift - callStackMod; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc index 461013022d..ebd9219e83 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc @@ -1138,7 +1138,7 @@ void Architecture::init(DocumentStorage &store) 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(); @@ -1148,6 +1148,7 @@ Address SegmentedResolver::resolve(uintb val,int4 sz,const Address &point) // (as with near pointers) if (segop->getResolve().space != (AddrSpace *)0) { uintb base = glb->context->getTrackedValue(segop->getResolve(),point); + fullEncoding = (base << 8 * innersz) + (val & calc_mask(innersz)); vector seginput; seginput.push_back(val); 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 + fullEncoding = val; int4 outersz = segop->getBaseSize(); uintb base = (val >> 8*innersz) & calc_mask(outersz); val = val & calc_mask(innersz); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh index 83d2db8c2a..cb361c36bd 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh @@ -284,7 +284,7 @@ public: /// \param sp is the segmented space /// \param sop is the segment operator 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 diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/cast.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/cast.cc index c3ede0cfea..cab50a048b 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/cast.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/cast.cc @@ -269,8 +269,14 @@ bool CastStrategyC::isSubpieceCast(Datatype *outtype,Datatype *intype,uint4 offs (outmeta!=TYPE_PTR)&& (outmeta!=TYPE_FLOAT)) return false; - if ((inmeta==TYPE_PTR)&&((outmeta!=TYPE_INT) && (outmeta!=TYPE_UINT))) - return false; //other casts don't make sense for pointers + if (inmeta==TYPE_PTR) { + 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; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc index ea10394d27..082f5bf206 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc @@ -827,14 +827,14 @@ int4 ActionShadowVar::apply(Funcdata &data) /// \param rampoint will hold the Address of the resolved symbol /// \param data is the function being analyzed /// \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; Architecture *glb = data.getArch(); Varnode *outvn; 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; } 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 if (bit_transitions(vn->getOffset(),vn->getSize()) < 3) 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; @@ -943,10 +943,11 @@ int4 ActionConstantPtr::apply(Funcdata &data) else if ((opc == CPUI_PTRSUB)||(opc==CPUI_PTRADD)) continue; 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 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)) data.opSwapInput(op,0,1); count += 1; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh index 5c86fc30e2..56e4dc2dd1 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh @@ -162,7 +162,7 @@ public: /// \brief Check for constants, with pointer type, that correspond to global symbols class ActionConstantPtr : public Action { 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: ActionConstantPtr(const string &g) : Action(0,"constantptr",g) {} ///< Constructor virtual void reset(Funcdata &data) { localcount = 0; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc index 234a581244..1d0064ccf6 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc @@ -333,7 +333,7 @@ void Funcdata::spacebaseConstant(PcodeOp *op,int4 slot,SymbolEntry *entry,const outvn = outvn2; 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()); Varnode *outvn2 = newUniqueOut(origsize,zextop); 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); 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); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc index 3d6e4a6d9f..2b233c46f8 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc @@ -1403,7 +1403,8 @@ bool PrintC::pushPtrCharConstant(uintb val,const TypePointer *ct,const Varnode * { if (val==0) return false; 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 (!glb->symboltab->getGlobalScope()->isReadOnly(stringaddr,1,Address())) return false; // Check that string location is readonly diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/translate.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/translate.cc index 209b1b776a..98582c96c2 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/translate.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/translate.cc @@ -485,15 +485,27 @@ AddrSpace *AddrSpaceManager::getSpaceByShortcut(char sc) const 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(); if (ind < resolvelist.size()) { AddressResolver *resolve = resolvelist[ind]; 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 = spc->wrapOffset(val); return Address(spc,val); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/translate.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/translate.hh index 6fc4b0db28..b0f4c48105 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/translate.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/translate.hh @@ -147,8 +147,9 @@ public: /// \param val is constant to be resolved to an address /// \param sz is the size of \e val in context. /// \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 - 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 @@ -249,7 +250,7 @@ public: AddrSpace *getConstantSpace(void) const; ///< Get the constant space 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 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 AddrSpace *getSpace(int4 i) const; ///< Get an address space via its index AddrSpace *getNextSpaceInOrder(AddrSpace *spc) const; ///< Get the next \e contiguous address space diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc index d575d55153..4e511230a4 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc @@ -1124,13 +1124,17 @@ Datatype *TypeSpacebase::getSubType(uintb off,uintb *newoff) const { Scope *scope = getMap(); - // uintb unoff = (uintb)(intb)off; // Make sure this is a sign-extension - Address addr(spaceid,spaceid->wrapOffset(off)); + off = AddrSpace::byteToAddress(off, spaceid->getWordSize()); // Convert from byte offset to address unit + // 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; // Assume symbol being referenced is address tied, // so we use empty usepoint - smallest = scope->queryContainer(addr,1,Address()); + smallest = scope->queryContainer(addr,1,nullPoint); if (smallest == (SymbolEntry *)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 { - return glb->resolveConstant(spaceid,off,sz,point); + uintb fullEncoding; + return glb->resolveConstant(spaceid,off,sz,point,fullEncoding); } void TypeSpacebase::saveXml(ostream &s) const diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileCallback.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileCallback.java index 498f7727fe..6cfced2521 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileCallback.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileCallback.java @@ -80,7 +80,7 @@ public class DecompileCallback { listing = program.getListing(); addrfactory = program.getAddressFactory(); dtmanage = dt; - default_extrapop = pcodecompilerspec.getCallStackMod(); + default_extrapop = pcodecompilerspec.getDefaultCallingConvention().getExtrapop(); cpool = null; nativeMessage = null; debug = null; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java index 5f4de44e8e..68cf219aa4 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java @@ -1393,8 +1393,8 @@ public class SleighLanguage implements Language { SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "index", element.getUnique()); int size = element.getSize(); // Size in bits - if (size == 20) { - // TODO: SegmentedAddressSpace shouldn't really return 20 + if (element instanceof SegmentedAddressSpace) { + // TODO: SegmentedAddressSpace shouldn't really return 21 size = 32; } if (size > 64) { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/BasicCompilerSpec.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/BasicCompilerSpec.java index f917908287..5017907935 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/BasicCompilerSpec.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/BasicCompilerSpec.java @@ -254,16 +254,6 @@ public class BasicCompilerSpec implements CompilerSpec { ctxsetting.add(new ContextSetting(reg, value, begad, endad)); } - @Override - public int getCallStackMod() { - return defaultModel.getExtrapop(); - } - - @Override - public int getCallStackShift() { - return defaultModel.getStackshift(); - } - @Override public PrototypeModel[] getCallingConventions() { return models; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/CompilerSpec.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/CompilerSpec.java index 98fc3f8dc3..3ad0a8b151 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/CompilerSpec.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/CompilerSpec.java @@ -89,22 +89,6 @@ public interface CompilerSpec { */ 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 */ diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/FunctionPrototype.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/FunctionPrototype.java index c1456a02d5..db3249972b 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/FunctionPrototype.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/FunctionPrototype.java @@ -112,16 +112,17 @@ public class FunctionPrototype { // function pointer, in which case forcing the void // causes the decompiler to drop real parameters. // At the moment, we turn on varargs if there are no params - if (voidimpliesdotdotdot && voidinputlock) + if (voidimpliesdotdotdot && voidinputlock) { dotdotdot = true; + } } /** * Populate Function Prototype from information attached to a function in the Program DB. * * @param f is the function to grab prototype from - * @param default_extrapop - * @param override_extrapop + * @param default_extrapop is the default extrapop to use if the function's is unknown + * @param override_extrapop is true if the extrapop should be overridden */ void grabFromFunction(Function f, int default_extrapop, boolean override_extrapop) { modelname = f.getCallingConventionName(); @@ -134,10 +135,12 @@ public class FunctionPrototype { returnstorage = returnparam.getVariableStorage(); SourceType sigSource = f.getSignatureSource(); - if (sigSource != SourceType.DEFAULT) + if (sigSource != SourceType.DEFAULT) { outputlock = DataType.DEFAULT != returntype; - else + } + else { outputlock = false; + } if ((returnstorage == null) || (!returnstorage.isValid())) { // Unassigned or otherwise invalid storage outputlock = false; @@ -162,7 +165,11 @@ public class FunctionPrototype { extrapop = default_extrapop; } 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 */ public int getNumParams() { - if (localsyms != null) + if (localsyms != null) { return localsyms.getNumParams(); + } return params.length; } @@ -198,8 +206,9 @@ public class FunctionPrototype { * if this prototype is not backed by a LocalSymbolMap */ public HighParam getParam(int i) { - if (localsyms != null) + if (localsyms != null) { return localsyms.getParam(i); + } return null; } @@ -299,36 +308,50 @@ public class FunctionPrototype { /** * 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) { res.append("\n"); res.append(" \n "); int sz = returntype.getLength(); if (sz < 0) { @@ -338,14 +361,16 @@ public class FunctionPrototype { if ((returnstorage != null) && returnstorage.isValid() && (!returnstorage.isVoidStorage())) { 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 + } String addrstring = Varnode.buildXMLAddress(returnstorage.getVarnodes(), logicalsize); res.append(addrstring).append("\n "); } - else + else { // Decompiler will use model for storage res.append("\n "); // Don't specify where return type is stored + } res.append(dtmanage.buildTypeRef(returntype, sz)); res.append(" \n"); @@ -370,8 +395,9 @@ public class FunctionPrototype { res.append("\">\n"); res.append(" \n "); // Blank address sz = dt.getLength(); - if (sz < 0) + if (sz < 0) { sz = 1; + } res.append(dtmanage.buildTypeRef(dt, sz)); res.append("\n"); } @@ -381,21 +407,22 @@ public class FunctionPrototype { } /** - * Parse the function prototype from an XML tree node. - * - * @param node XML tree node from a parsing of a larger XML document - * - * @throws PcodeXMLException + * Parse the function prototype from tag. + * @param parser is the XML document to parse + * @param dtmanage is the DataTypeManager used to parse data-type tags + * @throws PcodeXMLException for any problems parsing */ public void readPrototypeXML(XmlPullParser parser, PcodeDataTypeManager dtmanage) throws PcodeXMLException { XmlElement node = parser.start("prototype"); modelname = node.getAttribute("model"); String val = node.getAttribute("extrapop"); - if (val.equals("unknown")) + if (val.equals("unknown")) { extrapop = PrototypeModel.UNKNOWN_EXTRAPOP; - else + } + else { extrapop = SpecXmlUtils.decodeInt(val); + } modellock = false; if (node.hasAttribute("modellock")) { modellock = SpecXmlUtils.decodeBoolean(node.getAttribute("modellock")); @@ -434,16 +461,18 @@ public class FunctionPrototype { } XmlElement retel = parser.start("returnsym"); outputlock = false; - if (retel.hasAttribute("typelock")) + if (retel.hasAttribute("typelock")) { outputlock = SpecXmlUtils.decodeBoolean(retel.getAttribute("typelock")); + } parser.discardSubTree(); returnstorage = null; // For now don't use decompiler's return storage returntype = dtmanage.readXMLDataType(parser); parser.end(retel); XmlElement peeknode = parser.peek(); - if ((peeknode != null) && peeknode.isStart()) + if ((peeknode != null) && peeknode.isStart()) { parser.discardSubTree(); // The decompiler may return an tag + } parser.end(node); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/LanguageTranslatorAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/LanguageTranslatorAdapter.java index 85b235ae8e..22259a13c3 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/LanguageTranslatorAdapter.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/LanguageTranslatorAdapter.java @@ -539,16 +539,6 @@ class TemporaryCompilerSpec implements CompilerSpec { public void applyContextSettings(DefaultProgramContext ctx) { } - @Override - public int getCallStackMod() { - return newCompilerSpec.getCallStackMod(); - } - - @Override - public int getCallStackShift() { - return newCompilerSpec.getCallStackShift(); - } - @Override public PrototypeModel[] getCallingConventions() { return new PrototypeModel[0]; diff --git a/Ghidra/Processors/x86/data/languages/x86-16.cspec b/Ghidra/Processors/x86/data/languages/x86-16.cspec index e54096c734..f07cea0b16 100644 --- a/Ghidra/Processors/x86/data/languages/x86-16.cspec +++ b/Ghidra/Processors/x86/data/languages/x86-16.cspec @@ -85,7 +85,7 @@ - + @@ -111,7 +111,7 @@ - + diff --git a/Ghidra/Processors/x86/data/patterns/x86-16_default_patterns.xml b/Ghidra/Processors/x86/data/patterns/x86-16_default_patterns.xml index a9cc5d5a6a..c311272765 100644 --- a/Ghidra/Processors/x86/data/patterns/x86-16_default_patterns.xml +++ b/Ghidra/Processors/x86/data/patterns/x86-16_default_patterns.xml @@ -6,7 +6,8 @@ 0x4dcb 0.011... 1100.011 1100.010 .0.....0 0x00 - 0xc390 + 1100.010 .0.....0 0x00 0x90 + 0xc390 0xcb90 0xc3 @@ -15,6 +16,7 @@ 0x5589e5 0xc8 000....0 0x0000 0x8cd89045 + 0x8cd055