diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc index 74b587740f..fd8f9ad546 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc @@ -3924,9 +3924,9 @@ int4 ActionInputPrototype::apply(Funcdata &data) } } if (data.isHighOn()) - data.getFuncProto().updateInputTypes(triallist,&active); + data.getFuncProto().updateInputTypes(data,triallist,&active); else - data.getFuncProto().updateInputNoTypes(triallist,&active,data.getArch()->types); + data.getFuncProto().updateInputNoTypes(data,triallist,&active); } data.clearDeadVarnodes(); #ifdef OPACTION_DEBUG diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/database.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/database.cc index 2d42613a5c..b903651d57 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/database.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/database.cc @@ -1069,13 +1069,23 @@ void Scope::removeRange(AddrSpace *spc,uintb first,uintb last) /// In particular, the SymbolEntry is assumed to map the entire Symbol. /// \param entry is the given SymbolEntry /// \return a SymbolEntry which has been fully integrated -SymbolEntry *Scope::addMap(const SymbolEntry &entry) +SymbolEntry *Scope::addMap(SymbolEntry &entry) { // First set properties of this symbol based on scope // entry.symbol->flags |= Varnode::mapped; if (isGlobal()) entry.symbol->flags |= Varnode::persist; + else if (!entry.addr.isInvalid()) { + // If this is not a global scope, but the address is in the global discovery range + // we still mark the symbol as persistent + Scope *glbScope = glb->symboltab->getGlobalScope(); + Address addr; + if (glbScope->inScope(entry.addr, 1, addr)) { + entry.symbol->flags |= Varnode::persist; + entry.uselimit.clear(); // FIXME: Kludge for incorrectly generated XML + } + } SymbolEntry *res; int4 consumeSize = entry.symbol->getBytesConsumed(); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/database.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/database.hh index 4ec0aacc5f..b070a2a167 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/database.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/database.hh @@ -492,7 +492,7 @@ protected: /// \return the newly created SymbolEntry virtual SymbolEntry *addDynamicMapInternal(Symbol *sym,uint4 exfl,uint8 hash,int4 off,int4 sz, const RangeList &uselim)=0; - SymbolEntry *addMap(const SymbolEntry &entry); ///< Integrate a SymbolEntry into the range maps + SymbolEntry *addMap(SymbolEntry &entry); ///< Integrate a SymbolEntry into the range maps void setSymbolId(Symbol *sym,uint8 id) const { sym->symbolId = id; } ///< Adjust the id associated with a symbol public: #ifdef OPACTION_DEBUG diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc index 41d39816a8..0ce16d71e2 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc @@ -3182,9 +3182,10 @@ void FuncProto::cancelInjectId(void) /// given a list of Varnodes and their associated trial information, /// create an input parameter for each trial in order, grabbing data-type /// information from the Varnode. Any old input parameters are cleared. +/// \param data is the function containing the trial Varnodes /// \param triallist is the list of Varnodes /// \param activeinput is the trial container -void FuncProto::updateInputTypes(const vector &triallist,ParamActive *activeinput) +void FuncProto::updateInputTypes(Funcdata &data,const vector &triallist,ParamActive *activeinput) { if (isInputLocked()) return; // Input is locked, do no updating @@ -3195,15 +3196,25 @@ void FuncProto::updateInputTypes(const vector &triallist,ParamActive ParamTrial &trial(activeinput->getTrial(i)); if (trial.isUsed()) { Varnode *vn = triallist[trial.getSlot()-1]; - if (!vn->isMark()) { - ParameterPieces pieces; + if (vn->isMark()) continue; + ParameterPieces pieces; + if (vn->isPersist()) { + int4 sz; + pieces.addr = data.findDisjointCover(vn, sz); + if (sz == vn->getSize()) + pieces.type = vn->getHigh()->getType(); + else + pieces.type = data.getArch()->types->getBase(sz, TYPE_UNKNOWN); + pieces.flags = 0; + } + else { pieces.addr = trial.getAddress(); pieces.type = vn->getHigh()->getType(); pieces.flags = 0; - store->setInput(count,"",pieces); - count += 1; - vn->setMark(); // Make sure vn is used only once } + store->setInput(count,"",pieces); + count += 1; + vn->setMark(); } } for(int4 i=0;i &triallist,ParamActive /// This is accomplished in the same way as if there were data-types but instead of /// pulling a data-type from the Varnode, only the size is used. /// Undefined data-types are pulled from the given TypeFactory +/// \param data is the function containing the trial Varnodes /// \param triallist is the list of Varnodes /// \param activeinput is the trial container -/// \param factory is the given TypeFactory -void FuncProto::updateInputNoTypes(const vector &triallist,ParamActive *activeinput, - TypeFactory *factory) +void FuncProto::updateInputNoTypes(Funcdata &data,const vector &triallist,ParamActive *activeinput) { if (isInputLocked()) return; // Input is locked, do no updating store->clearAllInputs(); int4 count = 0; int4 numtrials = activeinput->getNumTrials(); + TypeFactory *factory = data.getArch()->types; for(int4 i=0;igetTrial(i)); if (trial.isUsed()) { Varnode *vn = triallist[trial.getSlot()-1]; - if (!vn->isMark()) { - ParameterPieces pieces; - pieces.type = factory->getBase(vn->getSize(),TYPE_UNKNOWN); - pieces.addr = trial.getAddress(); + if (vn->isMark()) continue; + ParameterPieces pieces; + if (vn->isPersist()) { + int4 sz; + pieces.addr = data.findDisjointCover(vn, sz); + pieces.type = factory->getBase(sz, TYPE_UNKNOWN); pieces.flags = 0; - store->setInput(count,"",pieces); - count += 1; - vn->setMark(); // Make sure vn is used only once } + else { + pieces.addr = trial.getAddress(); + pieces.type = factory->getBase(vn->getSize(),TYPE_UNKNOWN); + pieces.flags = 0; + } + store->setInput(count,"",pieces); + count += 1; + vn->setMark(); // Make sure vn is used only once } } for(int4 i=0;icheckInputSplit(loc,size,splitpoint); } - void updateInputTypes(const vector &triallist,ParamActive *activeinput); - void updateInputNoTypes(const vector &triallist,ParamActive *activeinput,TypeFactory *factory); + void updateInputTypes(Funcdata &data,const vector &triallist,ParamActive *activeinput); + void updateInputNoTypes(Funcdata &data,const vector &triallist,ParamActive *activeinput); void updateOutputTypes(const vector &triallist); void updateOutputNoTypes(const vector &triallist,TypeFactory *factory); void updateAllTypes(const vector &namelist,const vector &typelist,bool dtdtdt); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh index ed54dca411..5e57bba8e6 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh @@ -266,6 +266,8 @@ public: void adjustInputVarnodes(const Address &addr,int4 size); void deleteVarnode(Varnode *vn) { vbank.destroy(vn); } ///< Delete the given varnode + Address findDisjointCover(Varnode *vn,int4 &sz); ///< Find range covering given Varnode and any intersecting Varnodes + /// \brief Find the first input Varnode covered by the given range /// /// \param s is the size of the range in bytes diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_varnode.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_varnode.cc index 8f7862999b..d18dd0fb41 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_varnode.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_varnode.cc @@ -1308,6 +1308,35 @@ void Funcdata::splitUses(Varnode *vn) // Dead-code actions should remove original op } +/// Find the minimal Address range covering the given Varnode that doesn't split other Varnodes +/// \param vn is the given Varnode +/// \param sz is used to pass back the size of the resulting range +/// \return the starting address of the resulting range +Address Funcdata::findDisjointCover(Varnode *vn,int4 &sz) + +{ + Address addr = vn->getAddr(); + Address endaddr = addr + vn->getSize(); + VarnodeLocSet::const_iterator iter = vn->lociter; + + while(iter != beginLoc()) { + --iter; + Varnode *curvn = *iter; + Address curEnd = curvn->getAddr() + curvn->getSize(); + if (curEnd <= addr) break; + addr = curvn->getAddr(); + } + iter = vn->lociter; + while(iter != endLoc()) { + Varnode *curvn = *iter; + ++iter; + if (endaddr <= curvn->getAddr()) break; + endaddr = curvn->getAddr() + curvn->getSize(); + } + sz = (int4)(endaddr.getOffset() - addr.getOffset()); + return addr; +} + /// Search for \e addrtied Varnodes whose storage falls in the global Scope, then /// build a new global Symbol if one didn't exist before. void Funcdata::mapGlobals(void) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.cc index 3520b2383b..8e12a899de 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.cc @@ -66,7 +66,7 @@ LocationMap::iterator LocationMap::add(Address addr,int4 size,int4 pass,int4 &in /// describing the associated range and when it was heritaged. /// \param addr is the given address /// \return the iterator to the SizeMap entry or the end iterator is the address is unheritaged -LocationMap::iterator LocationMap::find(Address addr) +LocationMap::iterator LocationMap::find(const Address &addr) { iterator iter = themap.upper_bound(addr); // First range after address @@ -80,7 +80,7 @@ LocationMap::iterator LocationMap::find(Address addr) /// Return the pass number when the given address was heritaged, or -1 if it was not heritaged /// \param addr is the given address /// \return the pass number of -1 -int4 LocationMap::findPass(Address addr) const +int4 LocationMap::findPass(const Address &addr) const { map::const_iterator iter = themap.upper_bound(addr); // First range after address diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.hh index 025cfeb3db..ab75eea3c4 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.hh @@ -47,12 +47,12 @@ private: map themap; ///< Heritaged addresses mapped to range size and pass number public: iterator add(Address addr,int4 size,int4 pass,int4 &intersect); ///< Mark new address as \b heritaged - iterator find(Address addr); ///< Look up if/how given address was heritaged - int4 findPass(Address addr) const; ///< Look up if/how given address was heritaged - void erase(iterator iter) { themap.erase(iter); } ///< Remove a particular entry from the map - iterator begin(void) { return themap.begin(); } ///< Get starting iterator over heritaged ranges - iterator end(void) { return themap.end(); } ///< Get ending iterator over heritaged ranges - void clear(void) { themap.clear(); } ///< Clear the map of heritaged ranges + iterator find(const Address &addr); ///< Look up if/how given address was heritaged + int4 findPass(const Address &addr) const; ///< Look up if/how given address was heritaged + void erase(iterator iter) { themap.erase(iter); } ///< Remove a particular entry from the map + iterator begin(void) { return themap.begin(); } ///< Get starting iterator over heritaged ranges + iterator end(void) { return themap.end(); } ///< Get ending iterator over heritaged ranges + void clear(void) { themap.clear(); } ///< Clear the map of heritaged ranges }; /// \brief Priority queue for the phi-node (MULTIEQUAL) placement algorithm diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/LocalSymbolMap.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/LocalSymbolMap.java index ba1c4a3a77..26957d6755 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/LocalSymbolMap.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/LocalSymbolMap.java @@ -17,8 +17,7 @@ package ghidra.program.model.pcode; import java.util.*; -import ghidra.program.model.address.Address; -import ghidra.program.model.address.AddressIterator; +import ghidra.program.model.address.*; import ghidra.program.model.data.DataType; import ghidra.program.model.data.Undefined; import ghidra.program.model.listing.*; @@ -184,16 +183,18 @@ public class LocalSymbolMap { if (symbol != null) { id = symbol.getID(); } - Address defAddr = null; - if (!storage.isStackStorage()) { - defAddr = dbFunction.getEntryPoint().addWrap(local.getFirstUseOffset()); - } HighSymbol sym; if (storage.isHashStorage()) { + Address defAddr = dbFunction.getEntryPoint().addWrap(local.getFirstUseOffset()); sym = newDynamicSymbol(id, name, dt, storage.getFirstVarnode().getOffset(), defAddr); } else { + Address defAddr = null; + int addrType = storage.getFirstVarnode().getAddress().getAddressSpace().getType(); + if (addrType != AddressSpace.TYPE_STACK && addrType != AddressSpace.TYPE_RAM) { + defAddr = dbFunction.getEntryPoint().addWrap(local.getFirstUseOffset()); + } sym = newMappedSymbol(id, name, dt, storage, defAddr, -1); } sym.setTypeLock(istypelock);