isNameUsed added to DecompileCallback

This commit is contained in:
caheckman 2020-06-25 19:24:33 -04:00
parent 44ed318672
commit 05c3358fe4
9 changed files with 198 additions and 50 deletions

View file

@ -1420,23 +1420,6 @@ void Scope::getScopePath(vector<const Scope *> &vec) const
}
}
/// 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(nm))
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.
@ -2305,13 +2288,21 @@ void ScopeInternal::findByName(const string &name,vector<Symbol *> &res) const
}
}
bool ScopeInternal::isNameUsed(const string &name) const
bool ScopeInternal::isNameUsed(const string &nm,const Scope *op2) 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);
if (iter != nametree.end()) {
if ((*iter)->getName() == name)
return true;
}
Scope *par = getParent();
if (par == (Scope *)0 || par == op2)
return false;
if (par->getParent() == (Scope *)0) // Never recurse into global scope
return false;
return par->isNameUsed(nm, op2);
}
string ScopeInternal::buildVariableName(const Address &addr,

View file

@ -603,13 +603,14 @@ public:
/// \param res will contain any matching Symbols
virtual void findByName(const string &name,vector<Symbol *> &res) const=0;
/// \brief Check if the given name is used within \b this scope.
/// \brief Check if the given name is occurs within the given scope path.
///
/// 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;
/// 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)
virtual bool isNameUsed(const string &nm,const Scope *op2) const=0;
/// \brief Convert an \e external \e reference to the referenced function
///
@ -694,7 +695,6 @@ public:
string getFullName(void) const; ///< Get the full name of \b this Scope
void getNameSegments(vector<string> &vec) const; ///< Get the fullname of \b this in segments
void getScopePath(vector<const Scope *> &vec) const; ///< Get the ordered list of scopes up 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)
@ -766,7 +766,7 @@ public:
virtual SymbolEntry *findOverlap(const Address &addr,int4 size) const;
virtual void findByName(const string &name,vector<Symbol *> &res) const;
virtual bool isNameUsed(const string &name) const;
virtual bool isNameUsed(const string &nm,const Scope *op2) const;
virtual Funcdata *resolveExternalRefFunction(ExternRefSymbol *sym) const;
virtual string buildVariableName(const Address &addr,

View file

@ -421,3 +421,13 @@ SymbolEntry *ScopeGhidraNamespace::addMapInternal(Symbol *sym,uint4 exfl,const A
glb->symboltab->addRange(this,res->getAddr().getSpace(),res->getFirst(),res->getLast());
return res;
}
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<const ScopeGhidraNamespace *>(op2);
uint8 otherId = (otherScope != (const ScopeGhidraNamespace *)0) ? otherScope->getId() : 0;
return ghidra->isNameUsed(nm, scopeId, otherId);
}

View file

@ -90,7 +90,7 @@ public:
virtual SymbolEntry *findOverlap(const Address &addr,int4 size) const { throw LowlevelError("findOverlap unimplemented"); }
virtual void findByName(const string &name,vector<Symbol *> &res) const { throw LowlevelError("findByName unimplemented"); }
virtual bool isNameUsed(const string &name) const { throw LowlevelError("isNameUsed unimplemented"); }
virtual bool isNameUsed(const string &nm,const Scope *op2) const { throw LowlevelError("isNameUsed unimplemented"); }
virtual MapIterator begin(void) const { throw LowlevelError("begin unimplemented"); }
virtual MapIterator end(void) const { throw LowlevelError("end unimplemented"); }
@ -125,14 +125,16 @@ 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 {
ArchitectureGhidra *ghidra; ///< Connection to the Ghidra client
uint8 scopeId; ///< Internal id allowing Ghidra client to reference formal namespaces
virtual SymbolEntry *addMapInternal(Symbol *sym,uint4 exfl,const Address &addr,int4 off,int4 sz,
const RangeList &uselim);
public:
ScopeGhidraNamespace(const string &nm,uint8 id,Architecture *g)
: ScopeInternal(nm,g) { scopeId = id; } ///< Constructor
ScopeGhidraNamespace(const string &nm,uint8 id,ArchitectureGhidra *g)
: ScopeInternal(nm,g) { ghidra = g; scopeId = id; } ///< Constructor
uint8 getId(void) const { return scopeId; } ///< Get the Ghidra specific id
virtual bool isNameUsed(const string &nm,const Scope *op2) const;
};
#endif

View file

@ -81,6 +81,34 @@ int4 ArchitectureGhidra::readToAnyBurst(istream &s)
}
}
/// Read the string protocol start, a single character, then the protocol end.
/// If the character is a 't', return \b true, otherwise \b false.
/// \param s is the input stream from the client
/// \return the passed back boolean value
bool ArchitectureGhidra::readBoolStream(istream &s)
{
int4 c;
bool res;
int4 type = readToAnyBurst(s);
if (type != 14) throw JavaError("alignment","Expecting string");
c = s.get();
res = (c == 't');
c = s.get();
while(c==0) {
c = s.get();
}
if (c==1) {
c = s.get();
if (c == 15)
return res;
}
if (c<0) // If pipe closed, our parent process is probably dead
exit(1); // So we exit to avoid a runaway process
throw JavaError("alignment","Expecting string terminator");
}
/// Characters are read up to the next protocol marked and placed into a string.
/// The protocol marker is consumed and must indicate the end of a string
/// or an exception is thrown.
@ -534,6 +562,29 @@ Document *ArchitectureGhidra::getNamespacePath(uint8 id)
return readXMLAll(sin);
}
bool ArchitectureGhidra::isNameUsed(const string &nm,uint8 startId,uint8 stopId)
{
sout.write("\000\000\001\004",4);
writeStringStream(sout,"isNameUsed");
sout.write("\000\000\001\016",4); // Beginning of string header
sout << nm;
sout.write("\000\000\001\017",4);
sout.write("\000\000\001\016",4); // Beginning of string header
sout << hex << startId;
sout.write("\000\000\001\017",4);
sout.write("\000\000\001\016",4); // Beginning of string header
sout << hex << stopId;
sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4);
sout.flush();
readToResponse(sin);
bool res = readBoolStream(sin);
readResponseEnd(sin);
return res;
}
/// Get the name of the primary symbol at the given address.
/// This is used to fetch within function \e labels. Only a name is returned.
/// \param addr is the given address
@ -791,3 +842,25 @@ ArchitectureGhidra::ArchitectureGhidra(const string &pspec,const string &cspec,c
sendCcode = true;
sendParamMeasures = false;
}
bool ArchitectureGhidra::isDynamicSymbolName(const string &nm)
{
if (nm.size() < 8) return false; // 4 characters of prefix, at least 4 of address
if (nm[3] != '_') return false;
if (nm[0]=='F' && nm[1]=='U' && nm[2]=='N') {
}
else if (nm[0]=='D' && nm[1]=='A' && nm[2]=='T') {
}
else {
return false;
}
for(int4 i=nm.size()-4;i<nm.size();++i) {
char c = nm[i];
if (c>='0' && c<='9') continue;
if (c>='a' && c<='f') continue;
return false;
}
return true;
}

View file

@ -93,6 +93,7 @@ public:
Document *getMappedSymbolsXML(const Address &addr); ///< Get symbols associated with the given address
Document *getExternalRefXML(const Address &addr); ///< Retrieve a description of an external function
Document *getNamespacePath(uint8 id); ///< Get a description of a namespace path
bool isNameUsed(const string &nm,uint8 startId,uint8 stopId); ///< Is given name used along namespace path
string getCodeLabel(const Address &addr); ///< Retrieve a label at the given address
Document *getType(const string &name,uint8 id); ///< Retrieve a data-type description for the given name and id
Document *getComments(const Address &fad,uint4 flags); ///< Retrieve comments for a particular function
@ -131,6 +132,7 @@ public:
static void segvHandler(int4 sig); ///< Handler for a segment violation (SIGSEGV) signal
static int4 readToAnyBurst(istream &s); ///< Read the next message protocol marker
static bool readBoolStream(istream &s); ///< Read a boolean value from the client
static void readStringStream(istream &s,string &res); ///< Receive a string from the client
static void writeStringStream(ostream &s,const string &msg); ///< Send a string to the client
static void readToResponse(istream &s); ///< Read the query response protocol marker
@ -140,6 +142,8 @@ public:
static uint1 *readPackedStream(istream &s); ///< Read packed p-code op information
static uint1 *readPackedAll(istream &s); ///< Read a whole response as packed p-code op information
static void passJavaException(ostream &s,const string &tp,const string &msg);
static bool isDynamicSymbolName(const string &nm); ///< Check if name is of form FUN_.. or DAT_..
};
#endif