diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/flow.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/flow.cc index 328b9df243..2e4ffe091e 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/flow.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/flow.cc @@ -1177,6 +1177,8 @@ void FlowInfo::doInjection(InjectPayload *payload,InjectContext &icontext,PcodeO data.opMarkStartBasic(*iter); // as start of basic block } + if (payload->isIncidentalCopy()) + obank.markIncidentalCopy(firstop, lastop); obank.moveSequenceDead(firstop,lastop,op); // Move the injection to right after the call map::iterator viter = visited.find(op->getAddr()); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc index f32651aef5..25cb996ee5 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc @@ -4106,6 +4106,7 @@ int4 FuncCallSpecs::transferLockedInputParam(ProtoParameter *param) if (startaddr < curtrial.getAddress()) continue; Address trialend = curtrial.getAddress() + (curtrial.getSize() - 1); if (trialend < lastaddr) continue; + if (curtrial.isDefinitelyNotUsed()) return 0; // Trial has already been stripped return curtrial.getSlot(); } if (startaddr.getSpace()->getType() == IPTR_SPACEBASE) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_varnode.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_varnode.cc index 17341e4d49..65a6e788db 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_varnode.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_varnode.cc @@ -1341,13 +1341,7 @@ bool Funcdata::ancestorOpUse(int4 maxlevel,const Varnode *invn, return false; case CPUI_COPY: - if ((invn->getSpace()->getType()==IPTR_INTERNAL)||(invn->isAddrForce())) { - // Bit of a kludge to take into account - // uniq <- LOAD uniq=stackX - // <-> - // call( uniq ) call( uniq ) - // - // We follow copys into uniques + if ((invn->getSpace()->getType()==IPTR_INTERNAL)||def->isIncidentalCopy()||def->getIn(0)->isIncidentalCopy()) { if (!ancestorOpUse(maxlevel-1,def->getIn(0),op,trial)) return false; return true; } @@ -1442,7 +1436,8 @@ int4 AncestorRealistic::enterNode(State &state) case CPUI_SUBPIECE: // Extracting to a temporary, or to the same storage location, or otherwise incidental // are viewed as just another node on the path to traverse - if (op->getOut()->getSpace()->getType()==IPTR_INTERNAL||op->getIn(0)->isIncidentalCopy() + if (op->getOut()->getSpace()->getType()==IPTR_INTERNAL + || op->isIncidentalCopy() || op->getIn(0)->isIncidentalCopy() || (op->getOut()->overlap(*op->getIn(0)) == (int4)op->getIn(1)->getOffset())) { stateStack.push_back(State(op,0)); return enter_node; // Push into the new node @@ -1461,7 +1456,8 @@ int4 AncestorRealistic::enterNode(State &state) case CPUI_COPY: // Copies to a temporary, or between varnodes with same storage location, or otherwise incidental // are viewed as just another node on the path to traverse - if (op->getOut()->getSpace()->getType()==IPTR_INTERNAL||op->getIn(0)->isIncidentalCopy() + if (op->getOut()->getSpace()->getType()==IPTR_INTERNAL + || op->isIncidentalCopy() || op->getIn(0)->isIncidentalCopy() || (op->getOut()->getAddr() == op->getIn(0)->getAddr())) { stateStack.push_back(State(op,0)); return enter_node; // Push into the new node @@ -1471,7 +1467,7 @@ int4 AncestorRealistic::enterNode(State &state) do { Varnode *vn = op->getIn(0); if ((!vn->isMark())&&(vn->isInput())) { - if (vn->isUnaffected()||(!vn->isDirectWrite())) + if (!vn->isDirectWrite()) return pop_fail; } op = vn->getDef(); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc index d363a42d4f..4c25c59fca 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc @@ -770,6 +770,24 @@ void PcodeOpBank::moveSequenceDead(PcodeOp *firstop,PcodeOp *lastop,PcodeOp *pre deadlist.splice(previter,deadlist,firstop->insertiter,enditer); } +/// Incidental COPYs are not considered active use of parameter passing Varnodes by +/// parameter analysis algorithms. +/// \param firstop is the start of the range of incidental COPY ops +/// \param lastop is the end of the range of incidental COPY ops +void PcodeOpBank::markIncidentalCopy(PcodeOp *firstop,PcodeOp *lastop) + +{ + list::iterator iter = firstop->insertiter; + list::iterator enditer = lastop->insertiter; + ++enditer; + while(iter != enditer) { + PcodeOp *op = *iter; + ++iter; + if (op->code() == CPUI_COPY) + op->setAdditionalFlag(PcodeOp::incidental_copy); + } +} + /// Find the first PcodeOp at or after the given Address assuming they have not /// yet been broken up into basic blocks. Take into account delay slots. /// \param addr is the given Address diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/op.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/op.hh index eff509db7f..3b43d33e9c 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/op.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/op.hh @@ -106,7 +106,8 @@ public: special_prop = 0x8, ///< Does some special form of datatype propagation special_print = 0x10, ///< Op is marked for special printing modified = 0x20, ///< This op has been modified by the current action - warning = 0x40 ///< Warning has been generated for this op + warning = 0x40, ///< Warning has been generated for this op + incidental_copy = 0x80 ///< Treat this as \e incidental for parameter recovery algorithms }; private: TypeOp *opcode; ///< Pointer to class providing behavioral details of the operation @@ -197,6 +198,7 @@ public: bool hasThisPointer(void) const { return ((addlflags&PcodeOp::has_thisptr)!=0); } ///< Return \b true if this is a call taking 'this' parameter bool isConstructor(void) const { return ((addlflags&PcodeOp::is_constructor)!=0); } ///< Return \b true if this is call to a constructor bool isDestructor(void) const { return ((addlflags&PcodeOp::is_destructor)!=0); } ///< Return \b true if this is call to a destructor + bool isIncidentalCopy(void) const { return ((addlflags&PcodeOp::incidental_copy)!=0); } ///< Return \b true if \b this COPY is \e incidental /// \brief Return \b true if output is 1-bit boolean bool isCalculatedBool(void) const { return ((flags&(PcodeOp::calculated_bool|PcodeOp::booloutput))!=0); } /// \brief Return \b true if we have already examined this cpool @@ -267,6 +269,7 @@ public: void markDead(PcodeOp *op); ///< Mark the given PcodeOp as \e dead void insertAfterDead(PcodeOp *op,PcodeOp *prev); ///< Insert the given PcodeOp after a point in the \e dead list void moveSequenceDead(PcodeOp *firstop,PcodeOp *lastop,PcodeOp *prev); + void markIncidentalCopy(PcodeOp *firstop,PcodeOp *lastop); ///< Mark any COPY ops in the given range as \e incidental bool empty(void) const { return optree.empty(); } ///< Return \b true if there are no PcodeOps in \b this container PcodeOp *target(const Address &addr) const; ///< Find the first executing PcodeOp for a target address PcodeOp *findOp(const SeqNum &num) const; ///< Find a PcodeOp by sequence number diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeinject.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeinject.cc index 67a8deada7..15509e04ae 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeinject.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeinject.cc @@ -74,6 +74,8 @@ void InjectPayload::restoreXml(const Element *el) } else if (elname == "dynamic") dynamic = xml_readbool(el->getAttributeValue(i)); + else if (elname == "incidentalcopy") + incidentalCopy = xml_readbool(el->getAttributeValue(i)); } const List &list(el->getChildren()); List::const_iterator iter; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeinject.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeinject.hh index 5111e6beae..a2bb650ed5 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeinject.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeinject.hh @@ -87,15 +87,17 @@ protected: string name; ///< Formal name of the payload int4 type; ///< Type of this payload: CALLFIXUP_TYPE, CALLOTHERFIXUP_TYPE, etc. bool dynamic; ///< True if the injection is generated dynamically + bool incidentalCopy; ///< True if injected COPYs are considered \e incidental int4 paramshift; ///< Number of parameters shifted in the original call vector inputlist; ///< List of input parameters to this payload vector output; ///< List of output parameters static void readParameter(const Element *el,string &name,uint4 &size); void orderParameters(void); ///< Assign an index to parameters public: - InjectPayload(const string &nm,int4 tp) { name=nm; type=tp; paramshift=0; dynamic = false; } ///< Construct for use with restoreXml + InjectPayload(const string &nm,int4 tp) { name=nm; type=tp; paramshift=0; dynamic = false; incidentalCopy = false; } ///< Construct for use with restoreXml int4 getParamShift(void) const { return paramshift; } ///< Get the number of parameters shifted bool isDynamic(void) const { return dynamic; } ///< Return \b true if p-code in the injection is generated dynamically + bool isIncidentalCopy(void) const { return incidentalCopy; } int4 sizeInput(void) const { return inputlist.size(); } ///< Return the number of input parameters int4 sizeOutput(void) const { return output.size(); } ///< Return the number of output parameters InjectParameter &getInput(int4 i) { return inputlist[i]; } ///< Get the i-th input parameter diff --git a/Ghidra/Framework/SoftwareModeling/data/languages/language_common.rxg b/Ghidra/Framework/SoftwareModeling/data/languages/language_common.rxg index b0766ab4bb..61ae582e31 100644 --- a/Ghidra/Framework/SoftwareModeling/data/languages/language_common.rxg +++ b/Ghidra/Framework/SoftwareModeling/data/languages/language_common.rxg @@ -212,6 +212,9 @@ + + + diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeDataTypeManager.java index 126ec5825b..c32ab2e7b1 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeDataTypeManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeDataTypeManager.java @@ -120,9 +120,12 @@ public class PcodeDataTypeManager { } /** - * Find a data type with the given name. - * @param nm name of data type - * @return may return null if no data type exists with the given name + * Find a base/built-in data-type with the given name and/or id. If an id is provided and + * a corresponding data-type exists, this data-type is returned. Otherwise the first + * built-in data-type with a matching name is returned + * @param nm name of data-type + * @param idstr is an optional string containing a data-type id number + * @return the data-type object or null if no matching data-type exists */ public DataType findBaseType(String nm, String idstr) { long id = 0; @@ -242,8 +245,13 @@ public class PcodeDataTypeManager { } /** - * @param type to be converted - * @return either a typeref tag giving the name, or a full type tag + * Generate an XML tag describing the given data-type. Most data-types produce a tag, + * fully describing the data-type. Where possible a tag is produced, which just gives + * the name of the data-type, deferring a full description of the data-type. For certain simple or + * nameless data-types, a tag is emitted giving a full description. + * @param type is the data-type to be converted + * @param size is the size in bytes of the specific instance of the data-type + * @return a StringBuilder containing the XML tag */ public StringBuilder buildTypeRef(DataType type, int size) { if (type != null && type.getDataTypeManager() != progDataTypes) { @@ -424,7 +432,7 @@ public class PcodeDataTypeManager { resBuf.append(">\n"); for (long key : keys) { resBuf.append(""); }