diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/database.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/database.cc index 333289b617..09d9e60de0 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/database.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/database.cc @@ -260,6 +260,39 @@ SymbolEntry *Symbol::getMapEntry(const Address &addr) const return (SymbolEntry *)0; } +/// A value of 0 means the base Symbol name is visible and not overridden in the given use scope. +/// A value of 1 means the base name may be overridden, but the parent scope name is not. +/// The minimual number of names that distinguishes \b this Symbol uniquely within the +/// use scope is returned. +/// \param useScope is the given scope where \b this Symbol is being used +/// \return the number of (extra) names needed to distinguish \b this Symbol +int4 Symbol::getResolutionDepth(const Scope *useScope) const + +{ + if (scope == useScope) return 0; // Symbol is in scope where it is used + const Scope *distinguishScope = scope->findDistinguishingScope(useScope); + int4 depth = 0; + string distinguishName; + const Scope *terminatingScope; + if (distinguishScope == (const Scope *)0) { // Symbol scope is ancestor of use scope + distinguishName = name; + terminatingScope = scope; + } + else { + distinguishName = distinguishScope->getName(); + const Scope *currentScope = scope; + while(currentScope != distinguishScope) { // For any scope up to the distinguishing scope + depth += 1; // Print its name + currentScope = currentScope->getParent(); + } + depth += 1; // Also print the distinguishing scope name + terminatingScope = distinguishScope->getParent(); + } + if (useScope->isNameUsed(distinguishName,terminatingScope)) + depth += 1; // Name was overridden, we need one more distinguishing name + return depth; +} + /// \param s is the output stream void Symbol::saveXmlHeader(ostream &s) const @@ -1257,6 +1290,74 @@ void Scope::getNameSegments(vector &vec) const } } +/// Put the parent scopes of \b this into an array in order, starting with the global scope. +/// This scope itself will not be in the array. +/// \param vec is storage for the array of scopes +void Scope::getScopePath(vector &vec) const + +{ + int4 count = 0; + Scope *cur = parent; + while(cur != (Scope *)0) { // Count number of elements in path + count += 1; + cur = cur->parent; + } + vec.resize(count); + cur = parent; + while(cur != (Scope *)0) { + count -= 1; + vec[count] = cur; + cur = cur->parent; + } +} + +/// Test for the presence of a symbol with the given name in either \b this scope or +/// an ancestor scope up to but not including the given terminating scope. +/// If the name is used \b true is returned. +/// \param nm is the given name to test +/// \param op2 is the terminating ancestor scope (or null) +bool Scope::isNameUsed(const string &nm,const Scope *op2) const + +{ + const Scope *currentScope = this; + while(currentScope != op2) { + if (currentScope->isNameUsed(name)) + return true; + currentScope = currentScope->parent; + } + return false; +} + +/// Any two scopes share at least the \e global scope as a common ancestor. We find the first scope +/// that is \e not in common. The scope returned will always be an ancestor of \b this. +/// If \b this is an ancestor of the other given scope, then null is returned. +/// \param op2 is the other given Scope +/// \return the first ancestor Scope that is not in common or null +const Scope *Scope::findDistinguishingScope(const Scope *op2) const + +{ + if (this == op2) return (Scope *)0; // Quickly check most common cases + if (parent == op2) return this; + if (op2->parent == this) return op2; + if (parent == op2->parent) return this; + vector thisPath; + vector op2Path; + getScopePath(thisPath); + op2->getScopePath(op2Path); + int4 min = thisPath.size(); + if (op2Path.size() < min) + min = op2Path.size(); + for(int4 i=0;i &res) const } } +bool ScopeInternal::isNameUsed(const string &name) const + +{ + Symbol sym((Scope *)0,name,(Datatype *)0); + SymbolNameTree::const_iterator iter = nametree.lower_bound(&sym); + if (iter == nametree.end()) return false; + return ((*iter)->getName() == name); +} + string ScopeInternal::buildVariableName(const Address &addr, const Address &pc, Datatype *ct,int4 &index,uint4 flags) const diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/database.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/database.hh index 94eb3964b8..9f08675cdb 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/database.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/database.hh @@ -202,6 +202,7 @@ public: Scope *getScope(void) const { return scope; } ///< Get the scope owning \b this Symbol SymbolEntry *getFirstWholeMap(void) const; ///< Get the first entire mapping of the symbol SymbolEntry *getMapEntry(const Address &addr) const; ///< Get first mapping of the symbol that contains the given Address + int4 getResolutionDepth(const Scope *useScope) const; ///< Get the number of scope names to print to resolve symbol in given context void saveXmlHeader(ostream &s) const; ///< Save basic Symbol properties as XML attributes void restoreXmlHeader(const Element *el); ///< Restore basic Symbol properties from XML void saveXmlBody(ostream &s) const; ///< Save details of the Symbol to XML @@ -587,6 +588,14 @@ public: /// \param res will contain any matching Symbols virtual void findByName(const string &name,vector &res) const=0; + /// \brief Check if the given name is used within \b this scope. + /// + /// Only \b this scope is checked. If one or more symbols exist with the given name, + /// \b true is returned. + /// \param name is the given name to check for + /// \return \b true if the name is used within \b this scope + virtual bool isNameUsed(const string &name) const=0; + /// \brief Convert an \e external \e reference to the referenced function /// /// \param sym is the Symbol marking the external reference @@ -669,6 +678,9 @@ public: bool isSubScope(const Scope *scp) const; ///< Is this a sub-scope of the given Scope string getFullName(void) const; ///< Get the full name of \b this Scope void getNameSegments(vector &vec) const; ///< Get the fullname of \b this in segments + void getScopePath(vector &vec) const; ///< Get the ordered list of parent scopes to \b this + bool isNameUsed(const string &nm,const Scope *op2) const; ///< Is the given name in use within given scope path + const Scope *findDistinguishingScope(const Scope *op2) const; ///< Find first ancestor of \b this not shared by given scope Architecture *getArch(void) const { return glb; } ///< Get the Architecture associated with \b this Scope *getParent(void) const { return parent; } ///< Get the parent Scope (or NULL if \b this is the global Scope) Symbol *addSymbol(const string &name,Datatype *ct); ///< Add a new Symbol \e without mapping it to an address @@ -734,6 +746,7 @@ public: virtual SymbolEntry *findOverlap(const Address &addr,int4 size) const; virtual void findByName(const string &name,vector &res) const; + virtual bool isNameUsed(const string &name) const; virtual Funcdata *resolveExternalRefFunction(ExternRefSymbol *sym) const; virtual string buildVariableName(const Address &addr, diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/database_ghidra.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/database_ghidra.hh index f15d5897da..f3e44619b2 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/database_ghidra.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/database_ghidra.hh @@ -89,6 +89,7 @@ public: virtual SymbolEntry *findOverlap(const Address &addr,int4 size) const { throw LowlevelError("findOverlap unimplemented"); } virtual void findByName(const string &name,vector &res) const { throw LowlevelError("findByName unimplemented"); } + virtual bool isNameUsed(const string &name) const { throw LowlevelError("isNameUsed unimplemented"); } virtual MapIterator begin(void) const { throw LowlevelError("begin unimplemented"); } virtual MapIterator end(void) const { throw LowlevelError("end unimplemented"); }