From d4217fb814d61a1ba222d897ec26af6a4b770a91 Mon Sep 17 00:00:00 2001 From: caheckman <48068198+caheckman@users.noreply.github.com> Date: Mon, 29 Jun 2020 15:23:09 -0400 Subject: [PATCH] Facilitating namespaces in testing --- .../src/decompile/cpp/architecture.cc | 16 ++- .../src/decompile/cpp/architecture.hh | 2 +- .../src/decompile/cpp/consolemain.cc | 2 +- .../Decompiler/src/decompile/cpp/database.cc | 101 ++++++++++++++---- .../Decompiler/src/decompile/cpp/database.hh | 16 ++- .../src/decompile/cpp/database_ghidra.cc | 41 +++---- .../src/decompile/cpp/database_ghidra.hh | 11 +- .../Decompiler/src/decompile/cpp/grammar.y | 2 +- .../src/decompile/cpp/ifacedecomp.cc | 30 +++--- .../Decompiler/src/decompile/cpp/printjava.cc | 14 +++ .../Decompiler/src/decompile/cpp/printjava.hh | 1 + .../app/decompiler/DecompileCallback.java | 5 +- .../ghidra/app/decompiler/DecompileDebug.java | 8 ++ .../dex/analyzer/DexAnalysisState.java | 12 ++- 14 files changed, 181 insertions(+), 80 deletions(-) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc index e8285c1c7e..fb3123c178 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc @@ -276,16 +276,18 @@ void Architecture::clearAnalysis(Funcdata *fd) /// Symbols do not necessarily need to be available for the decompiler. /// This routine loads all the \e load \e image knows about into the symbol table -void Architecture::readLoaderSymbols(void) +/// \param delim is the delimiter separating namespaces from symbol base names +void Architecture::readLoaderSymbols(const string &delim) { if (loadersymbols_parsed) return; // already read - Scope *scope = symboltab->getGlobalScope(); loader->openSymbols(); loadersymbols_parsed = true; LoadImageFunc record; while(loader->getNextSymbol(record)) { - scope->addFunction(record.address,record.name); + string basename; + Scope *scope = symboltab->findCreateScopeFromSymbolName(record.name, delim, basename, (Scope *)0); + scope->addFunction(record.address,basename); } loader->closeSymbols(); } @@ -324,9 +326,13 @@ SegmentOp *Architecture::getSegmentOp(AddrSpace *spc) const void Architecture::setPrototype(const PrototypePieces &pieces) { - Funcdata *fd = symboltab->getGlobalScope()->queryFunction( pieces.name ); + string basename; + Scope *scope = symboltab->resolveScopeFromSymbolName(pieces.name, "::", basename, (Scope *)0); + if (scope == (Scope *)0) + throw ParseError("Unknown namespace: " + pieces.name); + Funcdata *fd = scope->queryFunction( basename ); if (fd == (Funcdata *)0) - throw ParseError("Unknown function name: "+pieces.name); + throw ParseError("Unknown function name: " + pieces.name); fd->getFuncProto().setPieces(pieces); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh index a27d801f82..496db81809 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh @@ -177,7 +177,7 @@ public: 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 + void readLoaderSymbols(const string &delim); ///< Read any symbols from loader into database void collectBehaviors(vector &behave) const; ///< Provide a list of OpBehavior objects SegmentOp *getSegmentOp(AddrSpace *spc) const; ///< Retrieve the \e segment op for the given space if any void setPrototype(const PrototypePieces &pieces); ///< Set the prototype for a particular function diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/consolemain.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/consolemain.cc index 97092c3342..9880890614 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/consolemain.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/consolemain.cc @@ -96,7 +96,7 @@ void IfcLoadFile::execute(istream &s) return; } if (capa->getName() == "xml") // If file is xml - dcp->conf->readLoaderSymbols(); // Read in loader symbols + dcp->conf->readLoaderSymbols("::"); // Read in loader symbols #ifdef OPACTION_DEBUG dcp->conf->setDebugStream(status->optr); #endif diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/database.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/database.cc index bb8f3afd1c..0bbdc35c52 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/database.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/database.cc @@ -1702,6 +1702,12 @@ bool Scope::isReadOnly(const Address &addr,int4 size,const Address &usepoint) co return ((flags & Varnode::readonly)!=0); } +Scope *ScopeInternal::buildSubScope(const string &nm) + +{ + return new ScopeInternal(nm,glb); +} + void ScopeInternal::addSymbolInternal(Symbol *sym) { @@ -2291,10 +2297,10 @@ void ScopeInternal::findByName(const string &name,vector &res) const bool ScopeInternal::isNameUsed(const string &nm,const Scope *op2) const { - Symbol sym((Scope *)0,name,(Datatype *)0); + Symbol sym((Scope *)0,nm,(Datatype *)0); SymbolNameTree::const_iterator iter = nametree.lower_bound(&sym); if (iter != nametree.end()) { - if ((*iter)->getName() == name) + if ((*iter)->getName() == nm) return true; } Scope *par = getParent(); @@ -2583,6 +2589,23 @@ void ScopeInternal::processHole(const Element *el) } } +/// \brief Parse a \ tag indicating a named symbol with no storage or data-type info +/// +/// Let the decompiler know that a name is occupied within the scope for isNameUsed queries, without +/// specifying storage and data-type information about the symbol. This is modeled currently by +/// creating an unmapped symbol. +/// \param el is the \ element +void ScopeInternal::processCollision(const Element *el) + +{ + const string &nm(el->getAttributeValue("name")); + SymbolNameTree::const_iterator iter = findFirstByName(nm); + if (iter == nametree.end()) { + Datatype *ct = glb->types->getBase(1,TYPE_INT); + addSymbol(nm,ct); + } +} + /// \brief Insert a Symbol into the \b nametree /// /// Duplicate symbol names are allowed for by establishing a deduplication id for the Symbol. @@ -2657,6 +2680,8 @@ void ScopeInternal::restoreXml(const Element *el) } else if (subel->getName() == "hole") processHole(subel); + else if (subel->getName() == "collision") + processCollision(subel); else throw LowlevelError("Unknown symbollist tag: "+subel->getName()); ++iter2; @@ -2911,6 +2936,22 @@ void Database::removeRange(Scope *scope,AddrSpace *spc,uintb first,uintb last) fillResolve(scope); } +/// Look for an immediate child scope by name in a given parent. If does not exist, +/// create a new scope with the name and attach it to the parent. +/// \param nm is the base name of the desired subscope +/// \param parent is the given parent scope to search +/// \return the subscope object either found or created +Scope *Database::findCreateSubscope(const string &nm,Scope *parent) + +{ + Scope *res = parent->resolveScope(nm); + if (res != (Scope *)0) + return res; + res = globalscope->buildSubScope(nm); + attachScope(res, parent); + return res; +} + /// An \e absolute \e path of Scope names must be provided, from the global /// Scope down to the desired Scope. If the first path name is blank (""), it /// matches the global Scope. If the first path name is not blank, the @@ -2945,8 +2986,8 @@ Scope *Database::resolveScope(const vector &subnames) const /// \param basename will hold the passed back base Symbol name /// \param start is the Scope to start drilling down from, or NULL for the global scope /// \return the Scope being referred to by the name -Scope *Database::resolveScopeSymbolName(const string &fullname,const string &delim,string &basename, - Scope *start) const +Scope *Database::resolveScopeFromSymbolName(const string &fullname,const string &delim,string &basename, + Scope *start) const { if (start == (Scope *)0) start = globalscope; @@ -2966,6 +3007,37 @@ Scope *Database::resolveScopeSymbolName(const string &fullname,const string &del return start; } +/// \brief Find and/or create Scopes associated with a qualified Symbol name +/// +/// The name is parsed using a \b delimiter that is passed in. The name can +/// be only partially qualified by passing in a starting Scope, which the +/// name is assumed to be relative to. Otherwise the name is assumed to be +/// relative to the global Scope. The unqualified (base) name of the Symbol +/// is passed back to the caller. Any missing scope in the path is created. +/// \param fullname is the qualified Symbol name +/// \param delim is the delimiter separating names +/// \param basename will hold the passed back base Symbol name +/// \param start is the Scope to start drilling down from, or NULL for the global scope +/// \return the Scope being referred to by the name +Scope *Database::findCreateScopeFromSymbolName(const string &fullname,const string &delim,string &basename, + Scope *start) +{ + if (start == (Scope *)0) + start = globalscope; + + string::size_type mark = 0; + string::size_type endmark; + for(;;) { + endmark = fullname.find(delim,mark); + if (endmark == string::npos) break; + string scopename = fullname.substr(mark,endmark-mark); + start = findCreateSubscope(scopename, start); + mark = endmark + delim.size(); + } + basename = fullname.substr(mark,endmark); + return start; +} + /// \brief Determine the lowest-level Scope which might contain the given address as a Symbol /// /// As currently implemented, this method can only find a \e namespace Scope. @@ -3114,28 +3186,13 @@ void Database::restoreXml(const Element *el) for(;iter!=list.end();++iter) { const Element *subel = *iter; - Scope *new_scope; string name; vector parnames; parseParentTag(subel,name,parnames); parnames.push_back(name); - new_scope = resolveScope(parnames); - if (new_scope == (Scope *)0) { - // Scope wasn't pre-existing - Scope *curscope = globalscope; - int4 i; - for(i=1;iresolveScope(parnames[i]); // Resolve through any pre-existing scopes - if (nextscope == (Scope *)0) break; - curscope = nextscope; - } - while(i != parnames.size()) { - new_scope = new ScopeInternal(parnames[i],glb); // Create any new scopes, up to and including - attachScope(new_scope,curscope); // the scope represented by this Element - curscope = new_scope; - i += 1; - } - } + Scope *new_scope = globalscope; + for(int4 i=1;irestoreXml(subel); } } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/database.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/database.hh index 396942d69c..10b2c0f547 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/database.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/database.hh @@ -418,7 +418,6 @@ class Scope { void attachScope(Scope *child); ///< Attach a new child Scope to \b this void detachScope(ScopeMap::iterator iter); ///< Detach a child Scope from \b this void assignId(uint4 val) { uniqueId = val; } ///< Let the database assign a unique id to \b this scope - protected: Architecture *glb; ///< Architecture of \b this scope string name; ///< Name of \b this scope @@ -453,6 +452,15 @@ protected: LabSymbol **addrmatch); const RangeList &getRangeTree(void) const { return rangetree; } ///< Access the address ranges owned by \b this Scope + + /// \brief Build an unattached Scope to be associated as a sub-scope of \b this + /// + /// This is a Scope object \e factory, intended to be called off of the global scope for building + /// global namespace scopes. Function scopes are handled differently. + /// \param nm is the name of the new scope + /// \return the new Scope object + virtual Scope *buildSubScope(const string &nm)=0; + virtual void restrictScope(Funcdata *f); ///< Convert \b this to a local Scope // These add/remove range are for scope \b discovery, i.e. we may @@ -719,9 +727,11 @@ public: /// a \b maptable, which is a list of rangemaps that own the SymbolEntry objects. class ScopeInternal : public Scope { void processHole(const Element *el); + void processCollision(const Element *el); void insertNameTree(Symbol *sym); SymbolNameTree::const_iterator findFirstByName(const string &name) const; protected: + virtual Scope *buildSubScope(const string &nm); ///< Build an unattached Scope to be associated as a sub-scope of \b this virtual void addSymbolInternal(Symbol *sym); virtual SymbolEntry *addMapInternal(Symbol *sym,uint4 exfl,const Address &addr,int4 off,int4 sz,const RangeList &uselim); virtual SymbolEntry *addDynamicMapInternal(Symbol *sym,uint4 exfl,uint8 hash,int4 off,int4 sz, @@ -858,7 +868,9 @@ public: void removeRange(Scope *scope,AddrSpace *spc,uintb first,uintb last); ///< Remove an address range from \e ownership of a Scope Scope *getGlobalScope(void) const { return globalscope; } ///< Get the global Scope Scope *resolveScope(const vector &subnames) const; ///< Look-up a Scope by name - Scope *resolveScopeSymbolName(const string &fullname,const string &delim,string &basename,Scope *start) const; + Scope *resolveScopeFromSymbolName(const string &fullname,const string &delim,string &basename,Scope *start) const; + Scope *findCreateSubscope(const string &nm,Scope *parent); /// Find (and if not found create) a specific subscope + Scope *findCreateScopeFromSymbolName(const string &fullname,const string &delim,string &basename,Scope *start); const Scope *mapScope(const Scope *qpoint,const Address &addr,const Address &usepoint) const; Scope *mapScope(Scope *qpoint,const Address &addr,const Address &usepoint); uint4 getProperty(const Address &addr) const { return flagbase.getValue(addr); } ///< Get boolean properties at the given address diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/database_ghidra.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/database_ghidra.cc index 44db04b378..3d4f47e952 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/database_ghidra.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/database_ghidra.cc @@ -16,6 +16,12 @@ #include "database_ghidra.hh" #include "funcdata.hh" +Scope *ScopeGhidra::buildSubScope(const string &nm) + +{ + return new ScopeGhidraNamespace(nm,ghidra); +} + /// \param g is the Architecture and connection to the Ghidra client ScopeGhidra::ScopeGhidra(ArchitectureGhidra *g) : Scope("",g,this) @@ -31,30 +37,6 @@ ScopeGhidra::~ScopeGhidra(void) delete cache; } -/// Ghidra may report that a Symbol is in a \e namespace. This method -/// creates a dedicated Scope object to hold such a Symbol. The immediate -/// parent for the new Scope must already exist. -/// \param nm is the name of the new \e namespace -/// \param id is the Ghidra specific id associated with the namespace -/// \param par is the parent Scope -/// \return the new \e namespace Scope -Scope *ScopeGhidra::createNewScope(const string &nm,uint8 id,Scope *par) const - -{ - Scope *newscope = par->resolveScope(nm); - if (newscope != (Scope *)0) { - // Its possible because of the way that we merge root namespaces that - // Ghidra has distinct namespace ids for namespaces that we want merged - // So we return any existing namespace even though the id is different. - return newscope; - } - newscope = new ScopeGhidraNamespace(nm,id,ghidra); - ghidra->symboltab->attachScope(newscope,par); - if (id != 0) - namespaceMap[id] = newscope; - return newscope; -} - /// The Ghidra client reports a \e namespace id associated with /// Symbol. Determine if a matching \e namespac Scope already exists in the cache and build /// it if it isn't. This may mean creating a new \e namespace Scope. @@ -85,8 +67,13 @@ Scope *ScopeGhidra::reresolveScope(uint8 id) const s.unsetf(ios::dec | ios::hex | ios::oct); s >> scopeId; miter = namespaceMap.find(scopeId); - if (miter == namespaceMap.end()) - curscope = createNewScope(el->getContent(), scopeId, curscope); + if (miter == namespaceMap.end()) { + curscope = glb->symboltab->findCreateSubscope(el->getContent(), curscope); + ScopeGhidraNamespace *ghidraScope = (ScopeGhidraNamespace *)curscope; + if (ghidraScope->getClientId() == 0) + ghidraScope->setClientId(scopeId); + namespaceMap[scopeId] = curscope; + } else curscope = (*miter).second; } @@ -428,6 +415,6 @@ bool ScopeGhidraNamespace::isNameUsed(const string &nm,const Scope *op2) const if (ArchitectureGhidra::isDynamicSymbolName(nm)) return false; // Just assume default FUN_ and DAT_ names don't collide const ScopeGhidraNamespace *otherScope = dynamic_cast(op2); - uint8 otherId = (otherScope != (const ScopeGhidraNamespace *)0) ? otherScope->getId() : 0; + uint8 otherId = (otherScope != (const ScopeGhidraNamespace *)0) ? otherScope->getClientId() : 0; return ghidra->isNameUsed(nm, scopeId, otherId); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/database_ghidra.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/database_ghidra.hh index df3f3444ca..3f5e4e1af8 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/database_ghidra.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/database_ghidra.hh @@ -43,12 +43,12 @@ class ScopeGhidra : public Scope { Symbol *dump2Cache(Document *doc) const; ///< Parse a response into the cache Symbol *removeQuery(const Address &addr) const; ///< Process a query that missed the cache void processHole(const Element *el) const; ///< Process a response describing a hole - Scope *createNewScope(const string &nm,uint8 id,Scope *par) const; ///< Create a global \e namespace Scope Scope *reresolveScope(uint8 id) const; ///< Find the Scope that will contain a result Symbol virtual void addRange(AddrSpace *spc,uintb first,uintb last); virtual void removeRange(AddrSpace *spc,uintb first,uintb last) { throw LowlevelError("remove_range should not be performed on ghidra scope"); } + virtual Scope *buildSubScope(const string &nm); virtual void addSymbolInternal(Symbol *sym) { throw LowlevelError("add_symbol_internal unimplemented"); } virtual SymbolEntry *addMapInternal(Symbol *sym,uint4 exfl,const Address &addr,int4 off,int4 sz, const RangeList &uselim) { throw LowlevelError("addMap unimplemented"); } @@ -125,15 +125,18 @@ public: /// be a ScopeGhidra. This will query the Ghidra client on behalf of the \e namespace and /// register any new symbols with \b this Scope. class ScopeGhidraNamespace : public ScopeInternal { + friend class ScopeGhidra; ArchitectureGhidra *ghidra; ///< Connection to the Ghidra client uint8 scopeId; ///< Internal id allowing Ghidra client to reference formal namespaces + void setClientId(uint8 id) { scopeId = id; } +protected: virtual SymbolEntry *addMapInternal(Symbol *sym,uint4 exfl,const Address &addr,int4 off,int4 sz, const RangeList &uselim); public: - ScopeGhidraNamespace(const string &nm,uint8 id,ArchitectureGhidra *g) - : ScopeInternal(nm,g) { ghidra = g; scopeId = id; } ///< Constructor + ScopeGhidraNamespace(const string &nm,ArchitectureGhidra *g) + : ScopeInternal(nm,g) { ghidra = g; scopeId = 0; } ///< Constructor - uint8 getId(void) const { return scopeId; } ///< Get the Ghidra specific id + uint8 getClientId(void) const { return scopeId; } ///< Get the Ghidra specific id virtual bool isNameUsed(const string &nm,const Scope *op2) const; }; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/grammar.y b/Ghidra/Features/Decompiler/src/decompile/cpp/grammar.y index 3836408878..33141afdab 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/grammar.y +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/grammar.y @@ -524,7 +524,7 @@ uint4 GrammarLexer::moveState(char lookahead) } else if ((lookahead>='a')&&(lookahead<='z')) { } - else if (lookahead == '_') { + else if (lookahead == '_' || lookahead == ':') { } else { state = start; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ifacedecomp.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ifacedecomp.cc index 3ab5ae4b62..b0b2325e44 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ifacedecomp.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ifacedecomp.cc @@ -393,7 +393,7 @@ void IfcFuncload::execute(istream &s) throw IfaceExecutionError("No image loaded"); string basename; - Scope *funcscope = dcp->conf->symboltab->resolveScopeSymbolName(funcname,"::",basename,(Scope *)0); + Scope *funcscope = dcp->conf->symboltab->resolveScopeFromSymbolName(funcname,"::",basename,(Scope *)0); if (funcscope == (Scope *)0) throw IfaceExecutionError("Bad namespace: "+funcname); dcp->fd = funcscope->queryFunction( basename ); // Is function already in database @@ -438,7 +438,7 @@ void IfcReadSymbols::execute(istream &s) if (dcp->conf->loader == (LoadImage *)0) throw IfaceExecutionError("No binary loaded"); - dcp->conf->readLoaderSymbols(); + dcp->conf->readLoaderSymbols("::"); } void IfcMapaddress::execute(istream &s) @@ -460,9 +460,16 @@ void IfcMapaddress::execute(istream &s) Symbol *sym; uint4 flags = Varnode::namelock|Varnode::typelock; flags |= dcp->conf->symboltab->getProperty(addr); // Inherit existing properties - sym = dcp->conf->symboltab->getGlobalScope()->addSymbol(name,ct,addr,Address())->getSymbol(); + string basename; + Scope *scope = dcp->conf->symboltab->findCreateScopeFromSymbolName(name, "::", basename, (Scope *)0); + sym = scope->addSymbol(basename,ct,addr,Address())->getSymbol(); sym->getScope()->setAttribute(sym,flags); + if (scope->getParent() != (Scope *)0) { // If this is a global namespace scope + SymbolEntry *e = sym->getFirstWholeMap(); // Adjust range + dcp->conf->symboltab->addRange(scope,e->getAddr().getSpace(),e->getFirst(),e->getLast()); + } } + } void IfcMaphash::execute(istream &s) @@ -497,7 +504,9 @@ void IfcMapfunction::execute(istream &s) s >> name; // Read optional name if (name.empty()) dcp->conf->nameFunction(addr,name); // Pick default name if necessary - dcp->fd = dcp->conf->symboltab->getGlobalScope()->addFunction(addr,name)->getFunction(); + string basename; + Scope *scope = dcp->conf->symboltab->findCreateScopeFromSymbolName(name, "::", basename, (Scope *)0); + dcp->fd = scope->addFunction(addr,name)->getFunction(); string nocode; s >> ws >> nocode; @@ -1774,18 +1783,15 @@ void IfcPrintMap::execute(istream &s) if (dcp->conf == (Architecture *)0) throw IfaceExecutionError("No load image"); - if ((name=="global")||(dcp->fd==(Funcdata *)0)) { - scope = dcp->conf->symboltab->getGlobalScope(); - name = ""; + if (name.size() != 0 || dcp->fd==(Funcdata *)0) { + string fullname = name + "::a"; // Add fake variable name + scope = dcp->conf->symboltab->resolveScopeFromSymbolName(fullname, "::", fullname, (Scope *)0); } else scope = dcp->fd->getScopeLocal(); - if (name.size() != 0) { - scope = scope->resolveScope(name); - if (scope == (Scope *)0) - throw IfaceExecutionError("No map named: "+name); - } + if (scope == (Scope *)0) + throw IfaceExecutionError("No map named: "+name); *status->fileoptr << scope->getFullName() << endl; scope->printBounds(*status->fileoptr); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printjava.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/printjava.cc index eb8a91ae02..394c5e2538 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printjava.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printjava.cc @@ -46,6 +46,20 @@ PrintJava::PrintJava(Architecture *glb,const string &nm) : PrintC(glb,nm) castStrategy = new CastStrategyJava(); } +void PrintJava::docFunction(const Funcdata *fd) + +{ + bool singletonFunction = false; + if (curscope == (const Scope *)0) { + singletonFunction = true; + // Always assume we are in the scope of the parent class + pushScope(fd->getScopeLocal()->getParent()); + } + PrintC::docFunction(fd); + if (singletonFunction) + popScope(); +} + /// Print a data-type up to the identifier, store off array sizes /// for printing after the identifier. Find the root type (the one with an identifier) /// and the count number of wrapping arrays. diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printjava.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/printjava.hh index 14e8f2c522..fc62ab931f 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printjava.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printjava.hh @@ -59,6 +59,7 @@ class PrintJava : public PrintC { virtual void printUnicode(ostream &s,int4 onechar) const; public: PrintJava(Architecture *g,const string &nm="java-language"); ///< Constructor + virtual void docFunction(const Funcdata *fd); virtual void pushTypeStart(const Datatype *ct,bool noident); virtual void pushTypeEnd(const Datatype *ct); virtual bool doEmitWideCharPrefix(void) const { return false; } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileCallback.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileCallback.java index 8059b3e9fe..6674cc9567 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileCallback.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileCallback.java @@ -563,7 +563,7 @@ public class DecompileCallback { int pathSize = 0; Namespace curspace = namespace; long curId = namespace.getID(); - while (curId != stopId && curId != 0) { + while (curId != stopId && curId != 0 && !(curspace instanceof Library)) { pathSize += 1; curspace = curspace.getParentNamespace(); curId = curspace.getID(); @@ -592,6 +592,9 @@ public class DecompileCallback { } for (int i = 0; i < pathSize; ++i) { if (path[i] == id) { + if (debug != null) { + debug.nameIsUsed(symSpace, name); + } return true; } } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileDebug.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileDebug.java index 5114a058e0..16e12029e4 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileDebug.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileDebug.java @@ -677,6 +677,14 @@ public class DecompileDebug { cpool.add(buf.toString()); } + public void nameIsUsed(Namespace spc, String nm) { + StringBuilder buffer = new StringBuilder(); + buffer.append("\n"); + getMapped(spc, buffer.toString()); + } + public void addFlowOverride(Address addr,FlowOverride fo) { StringBuilder buf = new StringBuilder(); buf.append("DexAnalysisState which corresponds to the specified program instance. - * @param program + * @param program is the specified program instance * @return DexAnalysisState for specified program instance + * @throws IOException if there are problems during construction of the state object */ - public static DexAnalysisState getState(Program program) throws IOException { + public synchronized static DexAnalysisState getState(Program program) throws IOException { DexAnalysisState analysisState = AnalysisStateInfo.getAnalysisState(program, DexAnalysisState.class); if (analysisState == null) {