diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc index b2ac97b7c29..26e73972156 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc @@ -1223,6 +1223,7 @@ void ActionFuncLink::funcLinkInput(FuncCallSpecs *fc,Funcdata &data) } else data.opInsertInput(op,data.newVarnode(param->getSize(),param->getAddress()),op->numInput()); + data.segmentizeFarPtr(param->getType(), param->isTypeLocked(), op->getIn(op->numInput() - 1), false); } } if (spacebase != (AddrSpace *)0) { // If we need it, create the stackplaceholder @@ -1251,6 +1252,7 @@ void ActionFuncLink::funcLinkOutput(FuncCallSpecs *fc,Funcdata &data) int4 sz = outparam->getSize(); Address addr = outparam->getAddress(); data.newVarnodeOut(sz,addr,fc->getOp()); + data.segmentizeFarPtr(outparam->getType(), outparam->isTypeLocked(), fc->getOp()->getOut(), false); VarnodeData vdata; OpCode res = fc->assumedOutputExtension(addr,sz,vdata); if (res == CPUI_PIECE) { // Pick an extension based on type @@ -4282,6 +4284,23 @@ int4 ActionInferTypes::apply(Funcdata &data) } return 0; } + if (localcount == 0) { + Datatype* ct; + Varnode* vn; + VarnodeLocSet::const_iterator iter; + + for (iter = data.beginLoc(); iter != data.endLoc(); ++iter) { + vn = *iter; + if (vn->isAnnotation()) continue; + if ((!vn->isWritten()) && (vn->hasNoDescend())) continue; + ct = vn->getLocalType(); + bool bBegin = false; + if (iter == data.beginLoc()) bBegin = true; else iter--; + data.segmentizeFarPtr(ct, vn->isTypeLock(), vn, true); + if (bBegin) iter = data.beginLoc(); else iter++; + } + } + buildLocaltypes(data); // Set up initial types (based on local info) for(iter=data.beginLoc();iter!=data.endLoc();++iter) { vn = *iter; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc index 13308f7604b..1bac2ec7caa 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc @@ -343,6 +343,71 @@ void Funcdata::spacebaseConstant(PcodeOp *op,int4 slot,SymbolEntry *entry,const opSetInput(op,outvn,slot); } +void Funcdata::segmentizeFarPtr(Datatype* ct, bool locked, Varnode* vn, bool segmentize) +{ + SegmentOp* segdef = (SegmentOp*)0; + if ((ct->getMetatype() == TYPE_PTR || + ct->getMetatype() == TYPE_CODE) && locked) { + Architecture* glb = getArch(); + AddrSpace* rspc = glb->getDefaultSpace(); + bool arenearpointers = glb->hasNearPointers(rspc); + if (arenearpointers && rspc->getAddrSize() == vn->getSize()) + segdef = glb->userops.getSegmentOp(rspc->getIndex()); + } + //need to go through every single time this varnode is written to + if (segdef != (SegmentOp*)0 && vn->getDef() != (PcodeOp*)0 && !vn->isPtrCheck() && + vn->getDef()->code() != CPUI_SEGMENTOP && vn->getDef()->code() != CPUI_CALLOTHER) { + PcodeOp* segroot = vn->getDef(); + Varnode* outvn = newUnique(vn->getSize()); + opSetOutput(segroot, outvn); + PcodeOp* piece1 = newOp(2, segroot->getAddr()); + opSetOpcode(piece1, CPUI_SUBPIECE); + Varnode* vn1 = newUniqueOut(segdef->getBaseSize(), piece1); + opSetInput(piece1, outvn, 0); + opSetInput(piece1, newConstant(outvn->getSize(), segdef->getInnerSize()), 1); + opInsertAfter(piece1, segroot); + PcodeOp* piece2 = newOp(2, segroot->getAddr()); + opSetOpcode(piece2, CPUI_SUBPIECE); + Varnode* vn2 = newUniqueOut(segdef->getInnerSize(), piece2); + opSetInput(piece2, outvn, 0); + opSetInput(piece2, newConstant(outvn->getSize(), 0), 1); + opInsertAfter(piece2, piece1); + PcodeOp* newop = newOp(3, segroot->getAddr()); + opSetOutput(newop, vn); + opSetOpcode(newop, CPUI_CALLOTHER); + //endianness could matter here - e.g. CALLF addr16 on x86 uses segment(*:2 (ptr+2),*:2 ptr) + opSetInput(newop, newConstant(4, segdef->getIndex()), 0); + opSetInput(newop, vn1, 1); //need to check size of segment + opSetInput(newop, vn2, 2); //need to check size of offset + opInsertAfter(newop, piece2); + vn->setPtrCheck(); + outvn->setPtrCheck(); + + if (segmentize) {//FuncLinkInput/FuncLinkOutput come before segmentize, the rest require at least Spacebase for type locks + segroot = vn->getDef(); + vector bindlist; + bindlist.push_back((Varnode*)0); + bindlist.push_back((Varnode*)0); + if (!segdef->unify(*this, segroot, bindlist)) { + ostringstream err; + err << "Segment op in wrong form at "; + segroot->getAddr().printRaw(err); + throw LowlevelError(err.str()); + } + + if (segdef->getNumVariableTerms() == 1) + bindlist[1] = newConstant(4, 0); + // Redefine the op as a segmentop + opSetOpcode(segroot, CPUI_SEGMENTOP); + opSetInput(segroot, newVarnodeSpace(segdef->getSpace()), 0); + opSetInput(segroot, bindlist[1], 1); + opSetInput(segroot, bindlist[0], 2); + for (int4 j = segroot->numInput() - 1; j > 2; --j) // Remove anything else + opRemoveInput(segroot, j); + } + } +} + void Funcdata::clearCallSpecs(void) { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh index 9ced5d3f611..374690b76db 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh @@ -196,6 +196,7 @@ public: Varnode *newSpacebasePtr(AddrSpace *id); ///< Construct a new \e spacebase register for a given address space Varnode *findSpacebaseInput(AddrSpace *id) const; void spacebaseConstant(PcodeOp *op,int4 slot,SymbolEntry *entry,const Address &rampoint,uintb origval,int4 origsize); + void segmentizeFarPtr(Datatype* ct, bool locked, Varnode* vn, bool segmentize); /// \brief Get the number of heritage passes performed for the given address space ///