diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/cast.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/cast.cc index f11695524c..97c4a14322 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/cast.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/cast.cc @@ -231,7 +231,7 @@ Datatype *CastStrategyC::castStandard(Datatype *reqtype,Datatype *curtype, care_uint_int = true; isptr = true; } - if (curtype == reqtype) return (Datatype *)0; // Different typedefs could point to the same type + if (curbase == reqbase) return (Datatype *)0; // Different typedefs could point to the same type if ((reqbase->getMetatype()==TYPE_VOID)||(curtype->getMetatype()==TYPE_VOID)) return (Datatype *)0; // Don't cast from or to VOID if (reqbase->getSize() != curbase->getSize()) { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc index 4d7277572c..cd799f631f 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc @@ -76,7 +76,7 @@ void StackSolver::propagate(int4 varnum,int4 val) while(!workstack.empty()) { varnum = workstack.back(); workstack.pop_back(); - + eqn.var1 = varnum; top = lower_bound(eqs.begin(),eqs.end(),eqn,StackEqn::compare); while((top!=eqs.end())&&((*top).var1 == varnum)) { @@ -212,7 +212,7 @@ void StackSolver::build(const Funcdata &data,AddrSpace *id,int4 spcbase) } } } - + eqn.rhs = 4; // Otherwise make a guess guess.push_back(eqn); } @@ -274,7 +274,7 @@ void ActionStackPtrFlow::analyzeExtraPop(Funcdata &data,AddrSpace *stackspace,in } if (solver.getNumVariables() == 0) return; solver.solve(); // Solve the equations - + Varnode *invn = solver.getVariable(0); bool warningprinted = false; @@ -622,7 +622,7 @@ int4 ActionSegmentize::apply(Funcdata &data) vector bindlist; bindlist.push_back((Varnode *)0); bindlist.push_back((Varnode *)0); - + for(int4 i=0;iuserops.getSegmentOp(i); if (segdef == (SegmentOp *)0) continue; @@ -703,7 +703,7 @@ int4 ActionConstbase::apply(Funcdata &data) // PcodeOp *op; // list::const_iterator iter; // uintm hash; - + // for(iter=data.op_alive_begin();iter!=data.op_alive_end();++iter) { // op = *iter; // hash = op->getCseHash(); @@ -1384,7 +1384,7 @@ int4 ActionExtraPopSetup::apply(Funcdata &data) const VarnodeData &point(stackspace->getSpacebase(0)); Address sb_addr(point.space,point.offset); int4 sb_size = point.size; - + for(int4 i=0;igetExtraPop() == 0) continue; // Stack pointer is undisturbed @@ -1552,7 +1552,7 @@ int4 ActionParamDouble::apply(Funcdata &data) data.opSetInput(op,mostvn,slot+1); } count += 1; // Indicate that a change was made - + j -= 1; // Note we decrement j here, so that we can check nested CONCATs } } @@ -1573,7 +1573,7 @@ int4 ActionParamDouble::apply(Funcdata &data) else if (whole.inHandLo(vn1)) { if (whole.getHi() != vn2) continue; isslothi = false; - } + } else continue; if (fc->checkInputJoin(j,isslothi,vn1,vn2)) { @@ -1838,7 +1838,7 @@ int4 ActionReturnRecovery::apply(Funcdata &data) Varnode *vn; list::const_iterator iter,iterend; int4 i; - + int4 maxancestor = data.getArch()->trim_recurse_max; iterend = data.endOp(CPUI_RETURN); AncestorRealistic ancestorReal; @@ -1861,7 +1861,7 @@ int4 ActionReturnRecovery::apply(Funcdata &data) active->finishPass(); if (active->getNumPasses() > active->getMaxPass()) active->markFullyChecked(); - + if (active->isFullyChecked()) { data.getFuncProto().deriveOutputMap(active); iterend = data.endOp(CPUI_RETURN); @@ -1887,7 +1887,7 @@ int4 ActionRestrictLocal::apply(Funcdata &data) Varnode *vn; int4 i; vector::const_iterator eiter,endeiter; - + for(i=0;igetOp(); @@ -2126,7 +2126,7 @@ int4 ActionRestructureHigh::apply(Funcdata &data) l1->restructureHigh(); if (data.syncVarnodesWithSymbols(l1,true)) count += 1; - + #ifdef OPACTION_DEBUG if ((flags&rule_debug)==0) return 0; l1->turnOffDebug(); @@ -2151,7 +2151,7 @@ int4 ActionDefaultParams::apply(Funcdata &data) fc = data.getCallSpecs(i); if (!fc->hasModel()) { Funcdata *otherfunc = fc->getFuncdata(); - + if (otherfunc != (Funcdata *)0) { fc->copy(otherfunc->getFuncProto()); if ((!fc->isModelLocked())&&(!fc->hasMatchingModel(evalfp))) @@ -2165,6 +2165,36 @@ int4 ActionDefaultParams::apply(Funcdata &data) return 0; // Indicate success } +/// \brief Test if the given cast conflict can be resolved by passing to the first structure field +/// +/// Test if the given Varnode data-type is a pointer to a structure and if interpreting +/// the data-type as a pointer to the structure's first field will get it to match the +/// desired data-type. +/// \param vn is the given Varnode +/// \param ct is the desired data-type +/// \param castStrategy is used to determine if the data-types are compatible +/// \return \b true if a pointer to the first field makes sense +bool ActionSetCasts::testStructOffset0(Varnode *vn,Datatype *ct,CastStrategy *castStrategy) + +{ + if (ct->getMetatype() != TYPE_PTR) return false; + Datatype *highType = vn->getHigh()->getType(); + if (highType->getMetatype() != TYPE_PTR) return false; + Datatype *highPtrTo = ((TypePointer *)highType)->getPtrTo(); + if (highPtrTo->getMetatype() != TYPE_STRUCT) return false; + TypeStruct *highStruct = (TypeStruct *)highPtrTo; + if (highStruct->numDepend() == 0) return false; + vector::const_iterator iter = highStruct->beginField(); + if ((*iter).offset != 0) return false; + Datatype *reqtype = ((TypePointer *)ct)->getPtrTo(); + Datatype *curtype = (*iter).type; + if (reqtype->getMetatype() == TYPE_ARRAY) + reqtype = ((TypeArray *)reqtype)->getBase(); + if (curtype->getMetatype() == TYPE_ARRAY) + curtype = ((TypeArray *)curtype)->getBase(); + return (castStrategy->castStandard(reqtype, curtype, true, true) == (Datatype *)0); +} + /// \brief Insert cast to output Varnode type after given PcodeOp if it is necessary /// /// \param op is the given PcodeOp @@ -2229,7 +2259,7 @@ int4 ActionSetCasts::castInput(PcodeOp *op,int4 slot,Funcdata &data,CastStrategy { Datatype *ct; - Varnode *vn; + Varnode *vn,*vnout; PcodeOp *newop; ct = op->getOpcode()->getInputCast(op,slot,castStrategy); // Input type expected by this operation @@ -2253,16 +2283,29 @@ int4 ActionSetCasts::castInput(PcodeOp *op,int4 slot,Funcdata &data,CastStrategy if (vn->getType() == ct) return 1; } + else if (testStructOffset0(vn, ct, castStrategy)) { + // Insert a PTRSUB(vn,#0) instead of a CAST + newop = data.newOp(2,op->getAddr()); + vnout = data.newUniqueOut(vn->getSize(), newop); + vnout->updateType(ct,false,false); + vnout->setImplied(); + data.opSetOpcode(newop, CPUI_PTRSUB); + data.opSetInput(newop,vn,0); + data.opSetInput(newop,data.newConstant(4, 0),1); + data.opSetInput(op,vnout,slot); + data.opInsertBefore(newop,op); + return 1; + } newop = data.newOp(1,op->getAddr()); - vn = data.newUniqueOut(op->getIn(slot)->getSize(),newop); - vn->updateType(ct,false,false); - vn->setImplied(); + vnout = data.newUniqueOut(vn->getSize(),newop); + vnout->updateType(ct,false,false); + vnout->setImplied(); #ifdef CPUI_STATISTICS data.getArch()->stats->countCast(); #endif data.opSetOpcode(newop,CPUI_CAST); - data.opSetInput(newop,op->getIn(slot),0); - data.opSetInput(op,vn,slot); + data.opSetInput(newop,vn,0); + data.opSetInput(op,vnout,slot); data.opInsertBefore(newop,op); // Cast comes AFTER operation return 1; } @@ -2614,7 +2657,7 @@ int4 ActionMarkExplicit::baseExplicit(Varnode *vn,int4 maxref) desccount += 1; if (desccount > maxref) return -1; // Must not exceed max descendants } - + return desccount; } @@ -3010,7 +3053,7 @@ int4 ActionDoNothing::apply(Funcdata &data) int4 i; const BlockGraph &graph(data.getBasicBlocks()); BlockBasic *bb; - + for(i=0;iisDoNothing()) { @@ -3825,7 +3868,7 @@ int4 ActionPrototypeTypes::apply(Funcdata &data) data.opSetInput(op,vn,0); } } - + if (data.getFuncProto().isOutputLocked()) { ProtoParameter *outparam = data.getFuncProto().getOutput(); if (outparam->getType()->getMetatype() != TYPE_VOID) { @@ -3877,7 +3920,7 @@ int4 ActionPrototypeTypes::apply(Funcdata &data) BlockBasic *topbl = (BlockBasic *)0; if (data.getBasicBlocks().getSize() > 0) topbl = (BlockBasic *)data.getBasicBlocks().getBlock(0); - + int4 numparams = data.getFuncProto().numParams(); for(i=0;icode() == CPUI_PTRADD)&&(slot==0)) - return op->getIn(2)->getOffset(); - if ((op->code() == CPUI_PTRSUB)&&(slot==0)) - return op->getIn(1)->getOffset(); + if (op->code() == CPUI_PTRADD) { + if (slot != 0) return 1; + Varnode *constvn = op->getIn(1); + uintb mult = op->getIn(2)->getOffset(); + if (constvn->isConstant()) { + off = (constvn->getOffset() * mult) & calc_mask(constvn->getSize()) ; + return 0; + } + if (sz != 0 && (mult % sz) != 0) + return 1; + return 2; + } + if (op->code() == CPUI_PTRSUB) { + if (slot != 0) return 1; + off = op->getIn(1)->getOffset(); + return 0; + } if (op->code() == CPUI_INT_ADD) { Varnode *othervn = op->getIn(1-slot); // Check if othervn is an offset if (!othervn->isConstant()) { - if ((!othervn->isWritten())||(othervn->getDef()->code() != CPUI_INT_MULT)) - return -1; + if (othervn->isWritten()) { + PcodeOp *multop = othervn->getDef(); + if (multop->code() == CPUI_INT_MULT) { + Varnode *constvn = multop->getIn(1); + if (constvn->isConstant()) { + uintb mult = constvn->getOffset(); + if (mult == calc_mask(constvn->getSize())) // If multiplying by -1 + return 1; // Assume this is a pointer difference and don't propagate + if (sz != 0 && (mult % sz) !=0) + return 1; + } + return 2; + } + } + if (sz == 1) + return 2; + return 1; } if (othervn->getTempType()->getMetatype() == TYPE_PTR) // Check if othervn marked as ptr - return -1; - if (othervn->isConstant()) - return othervn->getOffset(); + return 1; + off = othervn->getOffset(); return 0; } - return -1; + return 1; } /// \brief Propagate a pointer data-type through an ADD operation. @@ -4240,30 +4316,24 @@ int4 ActionInferTypes::propagateAddPointer(PcodeOp *op,int4 slot) /// \param inslot is the edge to propagate along /// \return the transformed Datatype or the original output Datatype Datatype *ActionInferTypes::propagateAddIn2Out(TypeFactory *typegrp,PcodeOp *op,int4 inslot) - + { - Datatype *rettype = op->getIn(inslot)->getTempType(); // We know this is a pointer type - Datatype *tstruct = ((TypePointer *)rettype)->getPtrTo(); - int4 offset = propagateAddPointer(op,inslot); - if (offset==-1) return op->getOut()->getTempType(); // Doesn't look like a good pointer add - uintb uoffset = AddrSpace::addressToByte(offset,((TypePointer *)rettype)->getWordSize()); - if (tstruct->getSize() > 0 && !tstruct->isVariableLength()) - uoffset = uoffset % tstruct->getSize(); - if (uoffset==0) { - if (op->code() == CPUI_PTRSUB) // Go down at least one level - rettype = typegrp->downChain(rettype,uoffset); - if (rettype == (Datatype *)0) - rettype = op->getOut()->getTempType(); - } - else { - while(uoffset != 0) { - rettype = typegrp->downChain(rettype,uoffset); - if (rettype == (Datatype *)0) { - rettype = op->getOut()->getTempType(); // Don't propagate anything - break; - } - } + TypePointer *pointer = (TypePointer *)op->getIn(inslot)->getTempType(); // We know this is a pointer type + uintb uoffset; + int4 command = propagateAddPointer(uoffset,op,inslot,pointer->getPtrTo()->getSize()); + if (command == 1) return op->getOut()->getTempType(); // Doesn't look like a good pointer add + if (command != 2) { + uoffset = AddrSpace::addressToByte(uoffset,pointer->getWordSize()); + bool allowWrap = (op->code() != CPUI_PTRSUB); + do { + pointer = pointer->downChain(uoffset,allowWrap,*typegrp); + if (pointer == (TypePointer *)0) + return op->getOut()->getTempType(); + } while(uoffset != 0); } + Datatype *rettype = pointer; + if (rettype == (Datatype *)0) + rettype = op->getOut()->getTempType(); if (op->getIn(inslot)->isSpacebase()) { if (rettype->getMetatype() == TYPE_PTR) { TypePointer *ptype = (TypePointer *)rettype; @@ -4367,7 +4437,7 @@ bool ActionInferTypes::propagateGoodEdge(PcodeOp *op,int4 inslot,int4 outslot,Va /// \param outslot indicates the edge's output Varnode /// \return \b true if the data-type propagates bool ActionInferTypes::propagateTypeEdge(TypeFactory *typegrp,PcodeOp *op,int4 inslot,int4 outslot) - + { Varnode *invn,*outvn; Datatype *newtype; @@ -4608,7 +4678,7 @@ void ActionInferTypes::propagateRef(Funcdata &data,Varnode *vn,const Address &ad } while(cur != (Datatype *)0); } if (lastct->getSize() != cursize) continue; - + // Try to propagate the reference type into a varnode that is pointed to by that reference if (0>lastct->typeOrder(*curvn->getTempType())) { #ifdef TYPEPROP_DEBUG @@ -4850,7 +4920,7 @@ void ActionDatabase::buildDefaultGroups(void) "cleanup", "merge", "dynamic", "casts", "analysis", "fixateglobals", "fixateproto", "segment", "returnsplit", "nodejoin", "doubleload", "doubleprecis", - "unreachable", "subvar", "floatprecision", + "unreachable", "subvar", "floatprecision", "conditionalexe", "" }; setGroup("decompile",members); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh index 7e0668a6aa..3e1390ab88 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh @@ -310,6 +310,7 @@ public: /// input. In this case, it casts to the necessary pointer type /// immediately. class ActionSetCasts : public Action { + static bool testStructOffset0(Varnode *vn,Datatype *ct,CastStrategy *castStrategy); static int4 castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStrategy); static int4 castInput(PcodeOp *op,int4 slot,Funcdata &data,CastStrategy *castStrategy); public: @@ -924,7 +925,7 @@ class ActionInferTypes : public Action { int4 localcount; ///< Number of passes performed for this function static void buildLocaltypes(Funcdata &data); ///< Assign initial data-type based on local info static bool writeBack(Funcdata &data); ///< Commit the final propagated data-types to Varnodes - static int4 propagateAddPointer(PcodeOp *op,int4 slot); ///< Test if edge is pointer plus a constant + static int4 propagateAddPointer(uintb &off,PcodeOp *op,int4 slot,int4 sz); ///< Test if edge is pointer plus a constant static Datatype *propagateAddIn2Out(TypeFactory *typegrp,PcodeOp *op,int4 inslot); static bool propagateGoodEdge(PcodeOp *op,int4 inslot,int4 outslot,Varnode *invn); static bool propagateTypeEdge(TypeFactory *typegrp,PcodeOp *op,int4 inslot,int4 outslot); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc index a3b4612e87..f645fc7295 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc @@ -361,7 +361,7 @@ void Funcdata::spacebaseConstant(PcodeOp *op,int4 slot,SymbolEntry *entry,const bool typelock = sym->isTypeLocked(); if (typelock && (entrytype->getMetatype() == TYPE_UNKNOWN)) typelock = false; - outvn->updateType(ptrentrytype,typelock,true); + outvn->updateType(ptrentrytype,typelock,false); if (extra != 0) { if (extraOp == (PcodeOp *)0) { extraOp = newOp(2,op->getAddr()); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc index a9c28db6c2..bb8a3201e2 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc @@ -6141,6 +6141,33 @@ bool RulePtrArith::verifyAddTreeBottom(PcodeOp *op,int4 slot) return true; } +/// \brief Test for other pointers in the ADD tree above the given op that might be a preferred base +/// +/// This tests the condition of RulePushPtr, making sure that the given op isn't the lone descendant +/// of a pointer constructed by INT_ADD on another pointer (which would then be preferred). +/// \param op is the given op +/// \param slot is the input slot of the pointer +/// \return \b true if the indicated slot holds the preferred pointer +bool RulePtrArith::verifyPreferredPointer(PcodeOp *op,int4 slot) + +{ + Varnode *vn = op->getIn(slot); + // Check if RulePushPtr would apply here + if (op->getIn(1-slot)->getType()->getMetatype() != TYPE_PTR && vn->isWritten()) { + PcodeOp *preOp = vn->getDef(); + if (preOp->code() == CPUI_INT_ADD) { + if (vn->loneDescend() == op) { + int ptrCount = 0; + if (preOp->getIn(0)->getType()->getMetatype() == TYPE_PTR) ptrCount += 1; + if (preOp->getIn(1)->getType()->getMetatype() == TYPE_PTR) ptrCount += 1; + if (ptrCount == 1) + return false; // RulePushPtr would apply, so we are not preferred + } + } + } + return true; +} + /// \class RulePtrArith /// \brief Transform pointer arithmetic /// @@ -6180,11 +6207,14 @@ int4 RulePtrArith::applyOp(PcodeOp *op,Funcdata &data) } if (slot == op->numInput()) return 0; if (!verifyAddTreeBottom(op, slot)) return 0; + if (!verifyPreferredPointer(op, slot)) return 0; const TypePointer *tp = (const TypePointer *) ct; ct = tp->getPtrTo(); // Type being pointed to int4 unitsize = AddrSpace::addressToByteInt(1,tp->getWordSize()); if (ct->getSize() == unitsize) { // Degenerate case + if (op->getOut()->getType()->getMetatype() != TYPE_PTR) // Make sure pointer propagates thru INT_ADD + return 0; vector newparams; newparams.push_back( op->getIn(slot) ); newparams.push_back( op->getIn(1-slot) ); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.hh index 8a0d0c4382..732689751a 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.hh @@ -1028,6 +1028,7 @@ public: }; class RulePtrArith : public Rule { static bool verifyAddTreeBottom(PcodeOp *op,int4 slot); + static bool verifyPreferredPointer(PcodeOp *op,int4 slot); public: RulePtrArith(const string &g) : Rule(g, 0, "ptrarith") {} ///< Constructor virtual Rule *clone(const ActionGroupList &grouplist) const { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc index 9739980821..10c02eddbc 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc @@ -556,6 +556,45 @@ void TypePointer::restoreXml(const Element *el,TypeFactory &typegrp) flags = ptrto->getInheritable(); } +/// \brief Find a sub-type pointer given an offset into \b this +/// +/// Add a constant offset to \b this pointer. +/// If there is a valid component at that offset, return a pointer +/// to the data-type of the component or NULL otherwise. +/// This routine only goes down one level at most. Pass back the +/// renormalized offset relative to the new data-type +/// \param off is a reference to the offset to add +/// \param allowArrayWrap is \b true if the pointer should be treated as a pointer to an array +/// \return a pointer datatype for the component or NULL +TypePointer *TypePointer::downChain(uintb &off,bool allowArrayWrap,TypeFactory &typegrp) + +{ + int4 ptrtoSize = ptrto->getSize(); + if (off >= ptrtoSize) { // Check if we are wrapping + if (ptrtoSize != 0 && !ptrto->isVariableLength()) { // Check if pointed-to is wrappable + if (!allowArrayWrap) + return (TypePointer *)0; + intb signOff = (intb)off; + sign_extend(signOff,size*8-1); + signOff = signOff % ptrtoSize; + if (signOff < 0) + signOff = signOff + ptrtoSize; + off = signOff; + if (off == 0) // If we've wrapped and are now at zero + return this; // consider this going down one level + } + } + + // If we know we have exactly one of an array, strip the array to get pointer to element + bool doStrip = (ptrto->getMetatype() != TYPE_ARRAY); + Datatype *pt = ptrto->getSubType(off,&off); + if (pt == (Datatype *)0) + return (TypePointer *)0; + if (doStrip) + return typegrp.getTypePointerStripArray(size, pt, wordsize); + return typegrp.getTypePointer(size,pt,wordsize); +} + void TypeArray::printRaw(ostream &s) const { @@ -2159,31 +2198,6 @@ void TypeFactory::destroyType(Datatype *ct) delete ct; } -/// Add a constant offset to a pointer with known data-type. -/// If there is a valid component at that offset, return a pointer -/// to the data-type of the component or NULL otherwise. -/// This routine only goes down one level at most. Pass back the -/// renormalized offset relative to the new data-type -/// \param ptrtype is the pointer data-type being added to -/// \param off is a reference to the offset to add -/// \return a pointer datatype for the component or NULL -Datatype *TypeFactory::downChain(Datatype *ptrtype,uintb &off) - -{ // Change ptr->struct => ptr->substruct - // where substruct starts at offset off - if (ptrtype->metatype != TYPE_PTR) return (Datatype *)0; - TypePointer *ptype = (TypePointer *)ptrtype; - Datatype *pt = ptype->ptrto; - // If we know we have exactly one of an array, strip the array to get pointer to element - bool doStrip = (pt->getMetatype() != TYPE_ARRAY); - pt = pt->getSubType(off,&off); - if (pt == (Datatype *)0) - return (Datatype *)0; - if (doStrip) - return getTypePointerStripArray(ptype->size, pt, ptype->getWordSize()); - return getTypePointer(ptype->size,pt,ptype->getWordSize()); -} - /// The data-type propagation system can push around data-types that are \e partial or are /// otherwise unrepresentable in the source language. This method substitutes those data-types /// with a concrete data-type that is representable, or returns the same data-type if is already concrete. diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh index aa79ae2dda..e318fe7308 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh @@ -248,6 +248,7 @@ public: virtual int4 compareDependency(const Datatype &op) const; // For tree structure virtual Datatype *clone(void) const { return new TypePointer(*this); } virtual void saveXml(ostream &s) const; + virtual TypePointer *downChain(uintb &off,bool allowArrayWrap,TypeFactory &typegrp); }; /// \brief Datatype object representing an array of elements @@ -451,7 +452,6 @@ public: const vector &intypes, bool dotdotdot); ///< Create a "function" datatype void destroyType(Datatype *ct); ///< Remove a data-type from \b this - Datatype *downChain(Datatype *ptrtype,uintb &off); ///< Find a sub-type matching a pointer and offset Datatype *concretize(Datatype *ct); ///< Convert given data-type to concrete form void dependentOrder(vector &deporder) const; ///< Place all data-types in dependency order void saveXml(ostream &s) const; ///< Save \b this container to stream diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc index 56ce320bc4..133d993103 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc @@ -1711,7 +1711,7 @@ Datatype *TypeOpPtrsub::getOutputToken(const PcodeOp *op,CastStrategy *castStrat TypePointer *ptype = (TypePointer *)op->getIn(0)->getHigh()->getType(); if (ptype->getMetatype() == TYPE_PTR) { uintb offset = AddrSpace::addressToByte(op->getIn(1)->getOffset(),ptype->getWordSize()); - Datatype *rettype = tlst->downChain(ptype,offset); + Datatype *rettype = ptype->downChain(offset,false,*tlst); if ((offset==0)&&(rettype != (Datatype *)0)) return rettype; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.cc index 7a651026cf..ba12e77f39 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.cc @@ -270,6 +270,7 @@ ScopeLocal::ScopeLocal(uint8 id,AddrSpace *spc,Funcdata *fd,Architecture *g) : S { space = spc; + deepestParamOffset = ~((uintb)0); rangeLocked = false; stackGrowsNegative = true; restrictScope(fd); @@ -310,12 +311,14 @@ void ScopeLocal::collectNameRecs(void) void ScopeLocal::resetLocalWindow(void) { + stackGrowsNegative = fd->getFuncProto().isStackGrowsNegative(); + deepestParamOffset = stackGrowsNegative ? ~((uintb)0) : 0; + if (rangeLocked) return; - localRange = fd->getFuncProto().getLocalRange(); + const RangeList &localRange( fd->getFuncProto().getLocalRange() ); const RangeList ¶mrange( fd->getFuncProto().getParamRange() ); - stackGrowsNegative = fd->getFuncProto().isStackGrowsNegative(); RangeList newrange; set::const_iterator iter; @@ -375,16 +378,13 @@ void ScopeLocal::markNotMapped(AddrSpace *spc,uintb first,int4 sz,bool parameter last = spc->getHighest(); if (parameter) { // Everything above parameter if (stackGrowsNegative) { - const Range *rng = localRange.getRange(spc,first); - if (rng != (const Range *)0) - first = rng->getFirst(); // Everything less is not mapped + if (first < deepestParamOffset) + deepestParamOffset = first; } else { - const Range *rng = localRange.getRange(spc,last); - if (rng != (const Range *)0) - last = rng->getLast(); // Everything greater is not mapped + if (first > deepestParamOffset) + deepestParamOffset = first; } - sz = (last-first)+1; } Address addr(space,first); // Remove any symbols under range @@ -427,6 +427,11 @@ string ScopeLocal::buildVariableName(const Address &addr, s << 'X'; // Indicate local stack space allocated by caller start = -start; } + else { + if (deepestParamOffset + 1 > 1 && stackGrowsNegative == (addr.getOffset() < deepestParamOffset)) { + s << 'Y'; // Indicate unusual region of stack + } + } s << dec << start; return makeNameUnique(s.str()); } @@ -1095,6 +1100,9 @@ void ScopeLocal::markUnaliased(const vector &alias) EntryMap *rangemap = maptable[space->getIndex()]; if (rangemap == (EntryMap *)0) return; list::iterator iter,enditer; + set::const_iterator rangeIter, rangeEndIter; + rangeIter = getRangeTree().begin(); + rangeEndIter = getRangeTree().end(); int4 alias_block_level = glb->alias_block_level; bool aliason = false; @@ -1105,31 +1113,39 @@ void ScopeLocal::markUnaliased(const vector &alias) enditer = rangemap->end_list(); while(iter!=enditer) { - if ((i 0xffff)) - aliason = false; - if (!aliason) - symbol->getScope()->setAttribute(symbol,Varnode::nolocalalias); - if (symbol->isTypeLocked() && alias_block_level != 0) { - if (alias_block_level == 3) - aliason = false; // For this level, all locked data-types block aliases - else { - type_metatype meta = symbol->getType()->getMetatype(); - if (meta == TYPE_STRUCT) - aliason = false; // Only structures block aliases - else if (meta == TYPE_ARRAY && alias_block_level > 1) - aliason = false; // Only arrays (and structures) block aliases - } + // Aliases shouldn't go thru unmapped regions of the local variables + while(rangeIter != rangeEndIter) { + const Range &rng(*rangeIter); + if (rng.getSpace() == space) { + if (rng.getFirst() > curalias && curoff >= rng.getFirst()) + aliason = false; + if (rng.getLast() >= curoff) break; // Check if symbol past end of mapped range + if (rng.getLast() > curalias) // If past end of range AND past last alias offset + aliason = false; // turn aliases off + } + ++rangeIter; + } + Symbol *symbol = entry.getSymbol(); + // Test if there is enough distance between symbol + // and last alias to warrant ignoring the alias + // NOTE: this is primarily to reset aliasing between + // stack parameters and stack locals + if (aliason && (curoff - curalias > 0xffff)) aliason = false; + if (!aliason) symbol->getScope()->setAttribute(symbol,Varnode::nolocalalias); + if (symbol->isTypeLocked() && alias_block_level != 0) { + if (alias_block_level == 3) + aliason = false; // For this level, all locked data-types block aliases + else { + type_metatype meta = symbol->getType()->getMetatype(); + if (meta == TYPE_STRUCT) + aliason = false; // Only structures block aliases + else if (meta == TYPE_ARRAY && alias_block_level > 1) aliason = false;// Only arrays (and structures) block aliases } } } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.hh index 8a4f9a0fdb..0944a3c975 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.hh @@ -195,10 +195,10 @@ public: /// portions are used for temporary storage (not mapped), and what portion is for parameters. class ScopeLocal : public ScopeInternal { AddrSpace *space; ///< Address space containing the local stack - RangeList localRange; ///< The set of addresses that might hold mapped locals (not parameters) list nameRecommend; ///< Symbol name recommendations for specific addresses list dynRecommend; ///< Symbol name recommendations for dynamic locations list typeRecommend; ///< Data-types for specific storage locations + uintb deepestParamOffset; ///< Deepest position of a parameter passed (to a called function) on the stack bool stackGrowsNegative; ///< Marked \b true if the stack is considered to \e grow towards smaller offsets bool rangeLocked; ///< True if the subset of addresses \e mapped to \b this scope has been locked bool adjustFit(RangeHint &a) const; ///< Make the given RangeHint fit in the current Symbol map