From 93471fb3eaee82440e30e45ee7da37036d2f563e Mon Sep 17 00:00:00 2001 From: caheckman <48068198+caheckman@users.noreply.github.com> Date: Sun, 17 Nov 2019 14:12:23 -0500 Subject: [PATCH] Simpler LanedRegister collection scheme --- .../src/decompile/cpp/architecture.cc | 63 ++++-- .../src/decompile/cpp/architecture.hh | 4 +- .../src/decompile/cpp/coreaction.cc | 195 ++++-------------- .../src/decompile/cpp/coreaction.hh | 31 +-- .../Decompiler/src/decompile/cpp/funcdata.hh | 16 +- .../src/decompile/cpp/funcdata_op.cc | 13 -- .../src/decompile/cpp/funcdata_varnode.cc | 15 ++ .../Decompiler/src/decompile/cpp/transform.cc | 16 +- .../Decompiler/src/decompile/cpp/transform.hh | 26 +-- 9 files changed, 136 insertions(+), 243 deletions(-) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc index e9ce1f91c2..f910610f77 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc @@ -220,6 +220,42 @@ AddrSpace *Architecture::getSpaceBySpacebase(const Address &loc,int4 size) const return (AddrSpace *)0; } +/// Look-up the laned register record associated with a specific storage location. Currently, the +/// record is only associated with the \e size of the storage, not its address. If there is no +/// associated record, null is returned. +/// \param loc is the starting address of the storage location +/// \param size is the size of the storage in bytes +/// \return the matching LanedRegister record or null +const LanedRegister *Architecture::getLanedRegister(const Address &loc,int4 size) const + +{ + int4 min = 0; + int4 max = lanerecords.size() - 1; + while(min <= max) { + int4 mid = (min + max) / 2; + int4 sz = lanerecords[mid].getWholeSize(); + if (sz < size) + min = mid + 1; + else if (size < sz) + max = mid - 1; + else + return &lanerecords[mid]; + } + return (const LanedRegister *)0; +} + +/// Return a size intended for comparison with a Varnode size to immediately determine if +/// the Varnode is a potential laned register. If there are no laned registers for the architecture, +/// -1 is returned. +/// \return the size in bytes of the smallest laned register or -1. +int4 Architecture::getMinimumLanedRegisterSize(void) const + +{ + if (lanerecords.empty()) + return -1; + return lanerecords[0].getWholeSize(); +} + /// The default model is used whenever an explicit model is not known /// or can't be determined. /// \param nm is the name of the model to set @@ -817,32 +853,23 @@ void Architecture::parseIncidentalCopy(const Element *el) void Architecture::parseLaneSizes(const Element *el) { + vector maskList; const List &childList(el->getChildren()); List::const_iterator iter; LanedRegister lanedRegister; // Only allocate once for(iter=childList.begin();iter!=childList.end();++iter) { if (lanedRegister.restoreXml(*iter, this)) { - lanerecords.push_back(lanedRegister); + int4 sizeIndex = lanedRegister.getWholeSize(); + while (maskList.size() <= sizeIndex) + maskList.push_back(0); + maskList[sizeIndex] |= lanedRegister.getSizeBitMask(); } } - if (lanerecords.empty()) return; - lanerecords.sort(); - - // Dedup records that are contained by (the following) records - list::iterator viter = lanerecords.begin(); - list::iterator nextiter = viter; - ++nextiter; - while(nextiter != lanerecords.end()) { - if ((*viter).contains(*nextiter)) { - lanerecords.erase(nextiter); - nextiter = viter; - ++nextiter; - } - else { - ++viter; - ++nextiter; - } + lanerecords.clear(); + for(int4 i=0;i inst; ///< Registered p-code instructions UserOpManage userops; ///< Specifically registered user-defined p-code ops vector splitrecords; ///< registers that we would prefer to see split for this processor - list lanerecords; ///< Vector registers that have preferred lane sizes + vector lanerecords; ///< Vector registers that have preferred lane sizes ActionDatabase allacts; ///< Actions that can be applied in this architecture bool loadersymbols_parsed; ///< True if loader symbols have been read #ifdef CPUI_STATISTICS @@ -167,6 +167,8 @@ public: bool hasModel(const string &nm) const; ///< Does this Architecture have a specific PrototypeModel bool highPtrPossible(const Address &loc,int4 size) const; ///< Are pointers possible to the given location? AddrSpace *getSpaceBySpacebase(const Address &loc,int4 size) const; ///< Get space associated with a \e spacebase register + const LanedRegister *getLanedRegister(const Address &loc,int4 size) const; ///< Get LanedRegister associated with storage + int4 getMinimumLanedRegisterSize(void) const; ///< Get the minimum size of a laned register in bytes void setDefaultModel(const string &nm); ///< Set the default PrototypeModel void clearAnalysis(Funcdata *fd); ///< Clear analysis specific to a function void readLoaderSymbols(void); ///< Read any symbols from loader into database diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc index 77b6a37c40..02188ff79b 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc @@ -495,127 +495,6 @@ int4 ActionStackPtrFlow::apply(Funcdata &data) return 0; } -/// Mark every PcodeOp that is reachable from the given Varnode and create a LanedAccess record. -/// \param data is the function to trace through -/// \param base is the description of the laned register being traced from -/// \param vn is the Varnode to trace -/// \param pos is the significance position of the Varnode within the laned register -void ActionCollectLanedAccess::traceVarnode(Funcdata &data,const LanedRegister *base,Varnode *vn,int4 pos) - -{ - list::const_iterator iter = vn->beginDescend(); - int4 step = 0; - while(step < 2) { - PcodeOp *op; - if (step == 0) { - op = *iter; - ++iter; - if (iter == vn->endDescend()) - step = 1; - } - else { - step = 2; - if (!vn->isWritten()) continue; - op = vn->getDef(); - } - if (op->isMark()) continue; - // Make sure op is associated with a lane access records describing its biggest Varnode - switch(op->code()) { - case CPUI_LOAD: - case CPUI_PIECE: - case CPUI_INT_ZEXT: - case CPUI_INT_SEXT: - if (vn != op->getOut()) continue; // Biggest Varnode is the output - break; - case CPUI_SUBPIECE: - if (vn != op->getIn(0)) continue; // Biggest Varnode is first input - break; - case CPUI_STORE: - if (vn != op->getIn(2)) continue; - break; - default: - break; - } - op->setMark(); - data.opMarkLanedAccess(base, op, vn->getSize(), pos); - } -} - -/// \brief Search for Varnodes that match the given laned vector register -/// -/// All varnodes (bigger than 8 bytes) that are contained in the vector register are processed, -/// looking for a working lane scheme. Data-flow from these Varnodes is traces and LanedAccess -/// records are created for each PcodeOp flowed through. -/// \param data is the function being traced -/// \param lanedRegister is the given register and acceptable lane schemes -/// \param iter is an iterator to the first Varnode that matches the vector register -void ActionCollectLanedAccess::processLane(Funcdata &data,const LanedRegister &lanedRegister, - VarnodeLocSet::const_iterator iter) -{ - int4 fullSize = lanedRegister.getStorage().size; - Address startAddress(lanedRegister.getStorage().getAddr()); - Address lastAddress(startAddress + (fullSize-1)); - VarnodeLocSet::const_iterator enditer = data.endLoc(); - while(iter != enditer) { - Varnode *vn = *iter; - ++iter; - if (lastAddress < vn->getAddr()) - break; - if (vn->getSize() <= 8) // Varnode not big enough to be vector register - continue; - int4 diff = (int4)(vn->getOffset() - startAddress.getOffset()); - if (diff + vn->getSize() > fullSize) // Must be contained by full register - continue; - if (vn->getSpace()->isBigEndian()) - diff = fullSize - (diff + vn->getSize()); - traceVarnode(data, &lanedRegister, vn, diff); - } -} - -/// Give each PcodeOp in the laned access list a chance to propagate to new PcodeOps, -/// which will have new records added to the list. -/// \param data is the function being traced -void ActionCollectLanedAccess::propagate(Funcdata &data) - -{ - list::const_iterator iter = data.beginLaneAccess(); - while(iter != data.endLaneAccess()) { - const LanedAccess lanedAccess( *iter ); - PcodeOp *op = lanedAccess.getOp(); - int4 sz = lanedAccess.getSize(); - for(int4 i=0;inumInput();++i) { - Varnode *vn = op->getIn(i); - if (vn->getSize() != sz) continue; // Size must match exactly - if (vn->isConstant() || vn->isAnnotation()) continue; - traceVarnode(data, lanedAccess.getBase(), vn, lanedAccess.getBytePos()); - } - ++iter; - } -} - -int4 ActionCollectLanedAccess::apply(Funcdata &data) - -{ - if (data.getArch()->lanerecords.empty()) - return 0; - const LanedRegister &lastRecord( data.getArch()->lanerecords.back() ); - Address lastAddress( lastRecord.getStorage().getAddr() + lastRecord.getStorage().size - 1); - list::const_iterator iter; - for(iter=data.getArch()->lanerecords.begin();iter!=data.getArch()->lanerecords.end();++iter) { - const LanedRegister &lanedRegister( *iter ); - VarnodeLocSet::const_iterator viter = data.beginLoc(lanedRegister.getStorage().getAddr()); - if (viter == data.endLoc()) break; - Varnode *vn = *viter; - if (lastAddress < vn->getAddr()) break; - processLane(data,lanedRegister,viter); - } - propagate(data); - list::const_iterator aiter; - for(aiter=data.beginLaneAccess();aiter!=data.endLaneAccess();++aiter) - (*aiter).getOp()->clearMark(); - return 0; -} - /// \brief Try to divide a single Varnode into lanes /// /// Look for a CPUI_SUBPIECE op that takes the given Varnode as the input or a @@ -626,15 +505,17 @@ int4 ActionCollectLanedAccess::apply(Funcdata &data) /// \param data is the function being transformed /// \param vn is the given single Varnode /// \param lanedRegister is acceptable set of lane sizes for the Varnode -/// \param bytePos is the significance position of the Varnode within the laned register /// \param allowDowncast is \b true if we allow lane systems with SUBPIECE terminators -bool ActionLaneDivide::processVarnode(Funcdata &data,Varnode *vn,const LanedRegister &lanedRegister,int4 bytePos, - bool allowDowncast) +/// \return \b true if the Varnode (and its data-flow) was successfully split +bool ActionLaneDivide::processVarnode(Funcdata &data,Varnode *vn,const LanedRegister &lanedRegister,bool allowDowncast) { list::const_iterator iter = vn->beginDescend(); LanedRegister checkedLanes; int4 step = 0; // 0 = descendants, 1 = def, 2 = done + if (iter == vn->endDescend()) { + step = 1; + } while(step < 2) { int4 curSize; // Putative lane size if (step == 0) { @@ -657,10 +538,8 @@ bool ActionLaneDivide::processVarnode(Funcdata &data,Varnode *vn,const LanedRegi } if (lanedRegister.allowedLane(curSize)) { if (checkedLanes.allowedLane(curSize)) continue; - checkedLanes.addSize(curSize); // Only check this scheme once - LaneDescription description(lanedRegister.getStorage().size,curSize); // Lane scheme dictated by curSize - if (!description.subset(bytePos,vn->getSize())) // Try to restrict lane scheme to actual Varnode - continue; + checkedLanes.addLaneSize(curSize); // Only check this scheme once + LaneDescription description(lanedRegister.getWholeSize(),curSize); // Lane scheme dictated by curSize LaneDivide laneDivide(&data,vn,description,allowDowncast); if (laneDivide.doTrace()) { laneDivide.apply(); @@ -675,31 +554,28 @@ bool ActionLaneDivide::processVarnode(Funcdata &data,Varnode *vn,const LanedRegi int4 ActionLaneDivide::apply(Funcdata &data) { - list::const_iterator iter; + map::const_iterator iter; bool allowDowncast = false; for(int4 i=0;i<2;++i) { for(iter=data.beginLaneAccess();iter!=data.endLaneAccess();++iter) { - const LanedAccess &lanedAccess(*iter); - PcodeOp *op = lanedAccess.getOp(); - if (op->isDead()) continue; - Varnode *vn = op->getOut(); - if (vn != (Varnode *)0 && vn->getSize() == lanedAccess.getSize()) - processVarnode(data, vn, *lanedAccess.getBase(), lanedAccess.getBytePos(), allowDowncast); - else { - for(int4 j=0;jnumInput();++j) { - vn = op->getIn(j); - if (vn->getSize() == lanedAccess.getSize()) { - if (!vn->isConstant() && !vn->isAnnotation() && !vn->isWritten()) { - processVarnode(data, vn, *lanedAccess.getBase(), lanedAccess.getBytePos(), allowDowncast); - break; - } - } + const LanedRegister *lanedReg = (*iter).second; + Address addr = (*iter).first.getAddr(); + int4 sz = (*iter).first.size; + VarnodeLocSet::const_iterator viter = data.beginLoc(sz,addr); + VarnodeLocSet::const_iterator venditer = data.endLoc(sz,addr); + while(viter != venditer) { + Varnode *vn = *viter; + if (processVarnode(data, vn, *lanedReg, allowDowncast)) { + viter = data.beginLoc(sz,addr); + venditer = data.endLoc(sz, addr); // Recalculate bounds } + else + ++viter; } } allowDowncast = true; } - data.clearLanedAccessList(); + data.clearLanedAccessMap(); return 0; } @@ -1238,14 +1114,30 @@ int4 ActionDeindirect::apply(Funcdata &data) return 0; } +/// Check if the given Varnode has a matching LanedRegister record. If so, add its +/// storage location to the given function's laned access list. +/// \param data is the given function +/// \param vn is the given Varnode +void ActionVarnodeProps::markLanedVarnode(Funcdata &data,Varnode *vn) + +{ + if (vn->isConstant()) return; + Architecture *glb = data.getArch(); + const LanedRegister *lanedRegister = glb->getLanedRegister(vn->getAddr(),vn->getSize()); + if (lanedRegister != (const LanedRegister *)0) + data.markLanedVarnode(vn,lanedRegister); +} + int4 ActionVarnodeProps::apply(Funcdata &data) { Architecture *glb = data.getArch(); bool cachereadonly = glb->readonlypropagate; - if (glb->userops.getVolatileRead() == (VolatileReadOp *)0) { - if (!cachereadonly) - return 0; // Nothing to do to special properties + int4 minLanedSize = 1000000; // Default size meant to filter no Varnodes + if (!data.isLanedRegComplete()) { + int4 sz = glb->getMinimumLanedRegisterSize(); + if (sz > 0) + minLanedSize = sz; } VarnodeLocSet::const_iterator iter; Varnode *vn; @@ -1254,6 +1146,9 @@ int4 ActionVarnodeProps::apply(Funcdata &data) while(iter != data.endLoc()) { vn = *iter++; // Advance iterator in case vn is deleted if (vn->isAnnotation()) continue; + int4 vnSize = vn->getSize(); + if (vnSize >= minLanedSize) + markLanedVarnode(data, vn); if (vn->hasActionProperty()) { if (cachereadonly&&vn->isReadOnly()) { if (data.fillinReadOnly(vn)) // Try to replace vn with its lookup in LoadImage @@ -1263,7 +1158,7 @@ int4 ActionVarnodeProps::apply(Funcdata &data) if (data.replaceVolatile(vn)) count += 1; // Try to replace vn with pcode op } - else if (((vn->getNZMask() & vn->getConsume())==0)&&(vn->getSize()<=sizeof(uintb))) { + else if (((vn->getNZMask() & vn->getConsume())==0)&&(vnSize<=sizeof(uintb))) { // FIXME: uintb should be arbitrary precision if (vn->isConstant()) continue; // Don't replace a constant if (vn->isWritten()) { @@ -1283,6 +1178,7 @@ int4 ActionVarnodeProps::apply(Funcdata &data) } } } + data.setLanedRegGenerated(); return 0; } @@ -4714,7 +4610,6 @@ void universal_action(Architecture *conf) // actmainloop->addAction( new ActionParamShiftStop("paramshift") ); actmainloop->addAction( new ActionRestrictLocal("localrecovery") ); // Do before dead code removed actmainloop->addAction( new ActionDeadCode("deadcode") ); - actmainloop->addAction( new ActionCollectLanedAccess("base") ); actmainloop->addAction( new ActionDynamicMapping("dynamic") ); // Must come before restructurevarnode and infertypes actmainloop->addAction( new ActionRestructureVarnode("localrecovery") ); actmainloop->addAction( new ActionSpacebase("base") ); // Must come before infertypes and nonzeromask diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh index 9e76efb3ae..dfec92b102 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh @@ -97,26 +97,6 @@ public: virtual int4 apply(Funcdata &data); }; -/// \brief Find PcodeOps that are accessing values from laned registers -/// -/// This looks for Varnodes that match any of the LanedRegister records associated with -/// the architecture. A record is created in the function's LanedAccess list for every -/// PcodeOp that accesses one of these Varnodes. These are later examined by ActionLaneDivide. -/// The LanedRegister is the key for finding the Varnode, but the \e big property can propagate -/// through data-flow to other Varnodes that are not necessarily using the same storage (i.e. uniques). -class ActionCollectLanedAccess : public Action { - void traceVarnode(Funcdata &data,const LanedRegister *base,Varnode *vn,int4 pos); ///< Trace a big Varnode instance to other big Varnodes - void processLane(Funcdata &data,const LanedRegister &lanedRegister,VarnodeLocSet::const_iterator iter); - void propagate(Funcdata &data); ///< Discover other PcodeOps that use laned values -public: - ActionCollectLanedAccess(const string &g) : Action(rule_onceperfunc,"collectlanedaccess",g) {} ///< Constructor - virtual Action *clone(const ActionGroupList &grouplist) const { - if (!grouplist.contains(getGroup())) return (Action *)0; - return new ActionCollectLanedAccess(getGroup()); - } - virtual int4 apply(Funcdata &data); -}; - /// \brief Find Varnodes with a vectorized lane scheme and attempt to split the lanes /// /// The Architecture lists (vector) registers that may be used to perform parallelized operations @@ -124,7 +104,7 @@ public: /// if a particular lane scheme makes sense in terms of the function's data-flow, and then /// rewrites the data-flow so that the lanes become explicit Varnodes. class ActionLaneDivide : public Action { - bool processVarnode(Funcdata &data,Varnode *vn,const LanedRegister &lanedRegister,int4 bytePos,bool allowDowncast); + bool processVarnode(Funcdata &data,Varnode *vn,const LanedRegister &lanedRegister,bool allowDowncast); public: ActionLaneDivide(const string &g) : Action(rule_onceperfunc,"lanedivide",g) {} ///< Constructor virtual Action *clone(const ActionGroupList &grouplist) const { @@ -222,8 +202,15 @@ public: virtual int4 apply(Funcdata &data); }; -/// \brief Transform read-only variables to constants +/// \brief Transform based on Varnode properties, such as \e read-only and \e volatile +/// +/// This performs various transforms that are based on Varnode properties. +/// - Read-only Varnodes are converted to the underlying constant +/// - Volatile Varnodes are converted read/write functions +/// - Varnodes whose values are not consumed are replaced with constant 0 Varnodes +/// - Large Varnodes are flagged for lane analysis class ActionVarnodeProps : public Action { + void markLanedVarnode(Funcdata &data,Varnode *vn); ///< Mark possible laned register storage public: ActionVarnodeProps(const string &g) : Action(0,"varnodeprops",g) {} ///< Constructor virtual Action *clone(const ActionGroupList &grouplist) const { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh index d7bb4760a4..1be92c13e0 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh @@ -56,7 +56,8 @@ class Funcdata { restart_pending = 0x200, ///< Analysis must be restarted (because of new override info) unimplemented_present = 0x400, ///< Set if function contains unimplemented instructions baddata_present = 0x800, ///< Set if function flowed into bad data - double_precis_on = 0x1000 ///< Set if we are performing double precision recovery + double_precis_on = 0x1000, ///< Set if we are performing double precision recovery + big_varnodes_generated = 0x2000 ///< Set when search for laned registers is complete }; uint4 flags; ///< Boolean properties associated with \b this function uint4 clean_up_index; ///< Creation index of first Varnode created after start of cleanup @@ -80,7 +81,7 @@ class Funcdata { Merge covermerge; ///< Variable range intersection algorithms ParamActive *activeoutput; ///< Data for assessing which parameters are passed to \b this function Override localoverride; ///< Overrides of data-flow, prototypes, etc. that are local to \b this function - list lanedList; ///< List of ops that are accessing potentially laned registers + map lanedMap; ///< Current storage locations which may be laned registers // Low level Varnode functions void setVarnodeProperties(Varnode *vn) const; ///< Look-up boolean properties and data-type information @@ -131,6 +132,8 @@ public: bool isTypeRecoveryOn(void) const { return ((flags&typerecovery_on)!=0); } ///< Has data-type recovery processes started bool hasNoCode(void) const { return ((flags & no_code)!=0); } ///< Return \b true if \b this function has no code body void setNoCode(bool val) { if (val) flags |= no_code; else flags &= ~no_code; } ///< Toggle whether \b this has a body + bool isLanedRegComplete(void) const { return ((flags&big_varnodes_generated)!=0); } ///< Have potential laned registers been generated + void setLanedRegGenerated(void) { flags |= big_varnodes_generated; } ///< Mark that laned registers have been collected /// \brief Toggle whether \b this is being used for jump-table recovery /// @@ -347,6 +350,11 @@ public: /// \brief End of (input or free) Varnodes at a given storage address VarnodeDefSet::const_iterator endDef(uint4 fl,const Address &addr) const { return vbank.endDef(fl,addr); } + void markLanedVarnode(Varnode *vn,const LanedRegister *lanedReg); ///< Mark Varnode as potential laned register + map::const_iterator beginLaneAccess(void) const { return lanedMap.begin(); } ///< Beginning iterator over laned accesses + map::const_iterator endLaneAccess(void) const { return lanedMap.end(); } ///< Ending iterator over laned accesses + void clearLanedAccessMap(void) { lanedMap.clear(); } ///< Clear records from the laned access list + HighVariable *findHigh(const string &name) const; ///< Find a high-level variable by name void mapGlobals(void); ///< Make sure there is a Symbol entry for all global Varnodes bool checkCallDoubleUse(const PcodeOp *opmatch,const PcodeOp *op,const Varnode *vn,const ParamTrial &trial) const; @@ -429,10 +437,6 @@ public: Varnode *opStackLoad(AddrSpace *spc,uintb off,uint4 sz,PcodeOp *op,Varnode *stackptr,bool insertafter); PcodeOp *opStackStore(AddrSpace *spc,uintb off,PcodeOp *op,bool insertafter); void opUndoPtradd(PcodeOp *op,bool finalize); ///< Convert a CPUI_PTRADD back into a CPUI_INT_ADD - void opMarkLanedAccess(const LanedRegister *base,PcodeOp *op,int4 sz,int4 pos); ///< Mark op as using laned register - list::const_iterator beginLaneAccess(void) const { return lanedList.begin(); } ///< Beginning iterator over laned accesses - list::const_iterator endLaneAccess(void) const { return lanedList.end(); } ///< Ending iterator over laned accesses - void clearLanedAccessList(void) { lanedList.clear(); } ///< Clear records from the laned access list /// \brief Start of PcodeOp objects with the given op-code list::const_iterator beginOp(OpCode opc) const { return obank.begin(opc); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_op.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_op.cc index 14fb27e935..c76eb65df9 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_op.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_op.cc @@ -557,19 +557,6 @@ void Funcdata::opUndoPtradd(PcodeOp *op,bool finalize) opInsertBefore(multOp,op); } -/// Store a record indicating a potential use of a large laned register. Generally, the output -/// of the op is the use, except in the case of SUBPIECE or STORE, where getIn(0) and getIn(2) -/// respectively are the Varnodes being used. -/// \param base is the description of the laned register that is triggering this record -/// \param op is the PcodeOp using the large Varnode -/// \param sz is the size of the large Varnode in bytes -/// \param pos is the significance position of the Varnode, relative to the LanedRegister description -void Funcdata::opMarkLanedAccess(const LanedRegister *base,PcodeOp *op,int4 sz,int4 pos) - -{ - lanedList.push_back(LanedAccess(base,op,sz,pos)); -} - /// Make a clone of the given PcodeOp, copying control-flow properties as well. The data-type /// is \e not cloned. /// \param op is the PcodeOp to clone diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_varnode.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_varnode.cc index ea47bc12c0..105e6f4d6a 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_varnode.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_varnode.cc @@ -286,6 +286,21 @@ void Funcdata::destroyVarnode(Varnode *vn) vbank.destroy(vn); } +/// Record the given Varnode as a potential laned register access. +/// The address and size of the Varnode is recorded, anticipating that new +/// Varnodes at the same storage location may be created +/// \param vn is the given Varnode to mark +/// \param lanedReg is the laned register record to associate with the Varnode +void Funcdata::markLanedVarnode(Varnode *vn,const LanedRegister *lanedReg) + +{ + VarnodeData storage; + storage.space = vn->getSpace(); + storage.offset = vn->getOffset(); + storage.size = vn->getSize(); + lanedMap[storage] = lanedReg; +} + /// Look up the Symbol visible in \b this function's Scope and return the HighVariable /// associated with it. If the Symbol doesn't exist or there is no Varnode holding at least /// part of the value of the Symbol, NULL is returned. diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/transform.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/transform.cc index aa3c857b17..484d615075 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/transform.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/transform.cc @@ -276,8 +276,10 @@ bool LanedRegister::restoreXml(const Element *el,const AddrSpaceManager *manage) } } if (laneSizes.empty()) return false; + VarnodeData storage; storage.space = (AddrSpace *)0; storage.restoreXml(el, manage); + wholeSize = storage.size; sizeBitMask = 0; string::size_type pos = 0; while(pos != string::npos) { @@ -299,23 +301,11 @@ bool LanedRegister::restoreXml(const Element *el,const AddrSpaceManager *manage) s >> sz; if (sz < 0 || sz > 16) throw LowlevelError("Bad lane size: " + value); - addSize(sz); + addLaneSize(sz); } return true; } -/// In order to return \b true, the storage for \b this must contain the storage for the other -/// LanedRegister, and every lane scheme of the other LanedRegister must also be a lane scheme -/// for \b this. -/// \param op2 is the other LanedRegister to check for containment -/// \return \b true if \b this contains the other register -bool LanedRegister::contains(const LanedRegister &op2) const - -{ - if (!storage.contains(op2.storage)) return false; - return ((sizeBitMask & op2.sizeBitMask) == op2.sizeBitMask); // Check for containment of lane size sets -} - TransformManager::~TransformManager(void) { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/transform.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/transform.hh index 2d61e67a62..c7f194b3eb 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/transform.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/transform.hh @@ -86,30 +86,16 @@ public: /// \brief Describes a (register) storage location and the ways it might be split into lanes class LanedRegister { - VarnodeData storage; ///< Defining characteristics of the register + int4 wholeSize; ///< Size of the whole register uint4 sizeBitMask; ///< A 1-bit for every permissible lane size public: - LanedRegister(void) { sizeBitMask = 0; } ///< Constructor + LanedRegister(void) { wholeSize = 0; sizeBitMask = 0; } ///< Constructor for use with restoreXml + LanedRegister(int4 sz,uint4 mask) { wholeSize = sz; sizeBitMask = mask; } ///< Constructor bool restoreXml(const Element *el,const AddrSpaceManager *manage); ///< Restore object from XML stream - const VarnodeData &getStorage(void) const { return storage; } ///< Get VarnodeData for storage - void addSize(int4 size) { sizeBitMask |= ((uint4)1 << size); } ///< Add a new \e size to the allowed list + int4 getWholeSize(void) const { return wholeSize; } ///< Get the size in bytes of the whole laned register + uint4 getSizeBitMask(void) const { return sizeBitMask; } ///< Get the bit mask of possible lane sizes + void addLaneSize(int4 size) { sizeBitMask |= ((uint4)1 << size); } ///< Add a new \e size to the allowed list bool allowedLane(int4 size) const { return (((sizeBitMask >> size) & 1) != 0); } ///< Is \e size among the allowed lane sizes - bool contains(const LanedRegister &op2) const; ///< Does \b this contain the given register and its possible lanes - bool operator<(const LanedRegister &op2) const { return (storage < op2.storage); } ///< Compare based on VarnodeData -}; - -/// \brief Record describing the access of a large Varnode that can be traced to a LanedRegister -class LanedAccess { - const LanedRegister *base; ///< Base register dictating the lane scheme - PcodeOp *op; ///< Operation using the big register - int4 size; ///< Size of the register in bytes - int4 bytePos; ///< Significance position relative to the laned register -public: - LanedAccess(const LanedRegister *b,PcodeOp *o,int4 sz,int4 pos) { base=b; op=o; size=sz; bytePos=pos; } ///< Constructor - const LanedRegister *getBase(void) const { return base; } ///< Get the base LanedRegister being traced - PcodeOp *getOp(void) const { return op; } ///< Get the PcodeOp using the large Varnode - int4 getSize(void) const { return size; } ///< Get the size of the Varnode being accessed - int4 getBytePos(void) const { return bytePos; } ///< Get the significance position relative to the laned register }; /// \brief Description of logical lanes within a \b big Varnode