mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
Merge remote-tracking branch 'origin/caheckman_EquateDeindirect'
This commit is contained in:
commit
0d2df489ce
43 changed files with 1050 additions and 396 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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<OpBehavior *> &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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1087,8 +1087,16 @@ SymbolEntry *ActionConstantPtr::isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op
|
|||
// Since we are looking for a global address
|
||||
// Assume it is address tied and use empty usepoint
|
||||
SymbolEntry *entry = data.getScopeLocal()->getParent()->queryContainer(rampoint,1,Address());
|
||||
if (needexacthit&&(entry != (SymbolEntry *)0)) {
|
||||
if (entry->getAddr() != rampoint)
|
||||
if (entry != (SymbolEntry *)0) {
|
||||
Datatype *ptrType = entry->getSymbol()->getType();
|
||||
if (ptrType->getMetatype() == TYPE_ARRAY) {
|
||||
Datatype *ct = ((TypeArray *)ptrType)->getBase();
|
||||
// In the special case of strings (character arrays) we allow the constant pointer to
|
||||
// refer to the middle of the string
|
||||
if (ct->isCharPrint())
|
||||
needexacthit = false;
|
||||
}
|
||||
if (needexacthit && entry->getAddr() != rampoint)
|
||||
return (SymbolEntry *)0;
|
||||
}
|
||||
return entry;
|
||||
|
@ -3916,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
|
||||
|
|
|
@ -295,18 +295,32 @@ int4 Symbol::getMapEntryPosition(const SymbolEntry *entry) const
|
|||
return -1;
|
||||
}
|
||||
|
||||
/// A value of 0 means the base Symbol name is visible and not overridden in the given use scope.
|
||||
/// For a given context scope where \b this Symbol is used, determine how many elements of
|
||||
/// the full namespace path need to be printed to correctly distinguish it.
|
||||
/// A value of 0 means the base symbol name is visible and not overridden in the context 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
|
||||
/// The minimal number of names that distinguishes the symbol name 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
|
||||
/// \param useScope is the given scope where the symbol is being used
|
||||
/// \return the number of (extra) names needed to distinguish the symbol
|
||||
int4 Symbol::getResolutionDepth(const Scope *useScope) const
|
||||
|
||||
{
|
||||
if (scope == useScope) return 0; // Symbol is in scope where it is used
|
||||
if (useScope == (const Scope *)0) { // Treat null useScope as resolving the full path
|
||||
const Scope *point = scope;
|
||||
int4 count = 0;
|
||||
while(point != (const Scope *)0) {
|
||||
count += 1;
|
||||
point = point->getParent();
|
||||
}
|
||||
return count-1; // Don't print global scope
|
||||
}
|
||||
if (depthScope == useScope)
|
||||
return depthResolution;
|
||||
depthScope = useScope;
|
||||
const Scope *distinguishScope = scope->findDistinguishingScope(useScope);
|
||||
int4 depth = 0;
|
||||
depthResolution = 0;
|
||||
string distinguishName;
|
||||
const Scope *terminatingScope;
|
||||
if (distinguishScope == (const Scope *)0) { // Symbol scope is ancestor of use scope
|
||||
|
@ -317,15 +331,15 @@ int4 Symbol::getResolutionDepth(const Scope *useScope) const
|
|||
distinguishName = distinguishScope->getName();
|
||||
const Scope *currentScope = scope;
|
||||
while(currentScope != distinguishScope) { // For any scope up to the distinguishing scope
|
||||
depth += 1; // Print its name
|
||||
depthResolution += 1; // Print its name
|
||||
currentScope = currentScope->getParent();
|
||||
}
|
||||
depth += 1; // Also print the distinguishing scope name
|
||||
depthResolution += 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;
|
||||
depthResolution += 1; // Name was overridden, we need one more distinguishing name
|
||||
return depthResolution;
|
||||
}
|
||||
|
||||
/// \param s is the output stream
|
||||
|
@ -564,7 +578,7 @@ Funcdata *FunctionSymbol::getFunction(void)
|
|||
{
|
||||
if (fd != (Funcdata *)0) return fd;
|
||||
SymbolEntry *entry = getFirstWholeMap();
|
||||
fd = new Funcdata(name,scope,entry->getAddr());
|
||||
fd = new Funcdata(name,scope,entry->getAddr(),this);
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
@ -586,7 +600,7 @@ void FunctionSymbol::restoreXml(const Element *el)
|
|||
|
||||
{
|
||||
if (el->getName() == "function") {
|
||||
fd = new Funcdata("",scope,Address());
|
||||
fd = new Funcdata("",scope,Address(),this);
|
||||
symbolId = fd->restoreXml(el);
|
||||
name = fd->getName();
|
||||
if (consumeSize < fd->getSize()) {
|
||||
|
@ -1055,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();
|
||||
|
@ -1377,43 +1401,25 @@ void Scope::getNameSegments(vector<string> &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<Scope *> &vec) const
|
||||
void Scope::getScopePath(vector<const Scope *> &vec) const
|
||||
|
||||
{
|
||||
int4 count = 0;
|
||||
Scope *cur = parent;
|
||||
while(cur != (Scope *)0) { // Count number of elements in path
|
||||
const Scope *cur = this;
|
||||
while(cur != (const Scope *)0) { // Count number of elements in path
|
||||
count += 1;
|
||||
cur = cur->parent;
|
||||
}
|
||||
vec.resize(count);
|
||||
cur = parent;
|
||||
while(cur != (Scope *)0) {
|
||||
cur = this;
|
||||
while(cur != (const 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.
|
||||
|
@ -1422,12 +1428,12 @@ bool Scope::isNameUsed(const string &nm,const Scope *op2) const
|
|||
const Scope *Scope::findDistinguishingScope(const Scope *op2) const
|
||||
|
||||
{
|
||||
if (this == op2) return (Scope *)0; // Quickly check most common cases
|
||||
if (this == op2) return (const Scope *)0; // Quickly check most common cases
|
||||
if (parent == op2) return this;
|
||||
if (op2->parent == this) return op2;
|
||||
if (op2->parent == this) return (const Scope *)0;
|
||||
if (parent == op2->parent) return this;
|
||||
vector<Scope *> thisPath;
|
||||
vector<Scope *> op2Path;
|
||||
vector<const Scope *> thisPath;
|
||||
vector<const Scope *> op2Path;
|
||||
getScopePath(thisPath);
|
||||
op2->getScopePath(op2Path);
|
||||
int4 min = thisPath.size();
|
||||
|
@ -1440,7 +1446,7 @@ const Scope *Scope::findDistinguishingScope(const Scope *op2) const
|
|||
if (min < thisPath.size())
|
||||
return thisPath[min]; // thisPath matches op2Path but is longer
|
||||
if (min < op2Path.size())
|
||||
return (Scope *)0; // op2Path matches thisPath but is longer
|
||||
return (const Scope *)0; // op2Path matches thisPath but is longer
|
||||
return this; // ancestor paths are identical (only base scopes differ)
|
||||
}
|
||||
|
||||
|
@ -1453,7 +1459,7 @@ Symbol *Scope::addSymbol(const string &name,Datatype *ct)
|
|||
{
|
||||
Symbol *sym;
|
||||
|
||||
sym = new Symbol(this,name,ct);
|
||||
sym = new Symbol(owner,name,ct);
|
||||
addSymbolInternal(sym); // Let this scope lay claim to the new object
|
||||
return sym;
|
||||
}
|
||||
|
@ -1474,7 +1480,7 @@ SymbolEntry *Scope::addSymbol(const string &name,Datatype *ct,
|
|||
{
|
||||
Symbol *sym;
|
||||
|
||||
sym = new Symbol(this,name,ct);
|
||||
sym = new Symbol(owner,name,ct);
|
||||
addSymbolInternal(sym);
|
||||
return addMapPoint(sym,addr,usepoint);
|
||||
}
|
||||
|
@ -1509,19 +1515,19 @@ Symbol *Scope::addMapSym(const Element *el)
|
|||
Symbol *sym;
|
||||
const string &symname( subel->getName() );
|
||||
if (symname == "symbol")
|
||||
sym = new Symbol(this);
|
||||
sym = new Symbol(owner);
|
||||
else if (symname == "dynsymbol")
|
||||
sym = new Symbol(this);
|
||||
sym = new Symbol(owner);
|
||||
else if (symname == "equatesymbol")
|
||||
sym = new EquateSymbol(this);
|
||||
sym = new EquateSymbol(owner);
|
||||
else if (symname == "function")
|
||||
sym = new FunctionSymbol(this,glb->min_funcsymbol_size);
|
||||
sym = new FunctionSymbol(owner,glb->min_funcsymbol_size);
|
||||
else if (symname == "functionshell")
|
||||
sym = new FunctionSymbol(this,glb->min_funcsymbol_size);
|
||||
sym = new FunctionSymbol(owner,glb->min_funcsymbol_size);
|
||||
else if (symname == "labelsym")
|
||||
sym = new LabSymbol(this);
|
||||
sym = new LabSymbol(owner);
|
||||
else if (symname == "externrefsymbol")
|
||||
sym = new ExternRefSymbol(this);
|
||||
sym = new ExternRefSymbol(owner);
|
||||
else
|
||||
throw LowlevelError("Unknown symbol type: "+symname);
|
||||
try { // Protect against duplicate scope errors
|
||||
|
@ -1563,7 +1569,7 @@ FunctionSymbol *Scope::addFunction(const Address &addr,const string &nm)
|
|||
errmsg += " overlaps object: "+overlap->getSymbol()->getName();
|
||||
glb->printMessage(errmsg);
|
||||
}
|
||||
sym = new FunctionSymbol(this,nm,glb->min_funcsymbol_size);
|
||||
sym = new FunctionSymbol(owner,nm,glb->min_funcsymbol_size);
|
||||
addSymbolInternal(sym);
|
||||
// Map symbol to base address of function
|
||||
// there is no limit on the applicability of this map within scope
|
||||
|
@ -1584,7 +1590,7 @@ ExternRefSymbol *Scope::addExternalRef(const Address &addr,const Address &refadd
|
|||
{
|
||||
ExternRefSymbol *sym;
|
||||
|
||||
sym = new ExternRefSymbol(this,refaddr,nm);
|
||||
sym = new ExternRefSymbol(owner,refaddr,nm);
|
||||
addSymbolInternal(sym);
|
||||
// Map symbol to given address
|
||||
// there is no limit on applicability of this map within scope
|
||||
|
@ -1612,7 +1618,7 @@ LabSymbol *Scope::addCodeLabel(const Address &addr,const string &nm)
|
|||
errmsg += " overlaps object: "+overlap->getSymbol()->getName();
|
||||
glb->printMessage(errmsg);
|
||||
}
|
||||
sym = new LabSymbol(this,nm);
|
||||
sym = new LabSymbol(owner,nm);
|
||||
addSymbolInternal(sym);
|
||||
addMapPoint(sym,addr,Address());
|
||||
return sym;
|
||||
|
@ -1632,7 +1638,7 @@ Symbol *Scope::addDynamicSymbol(const string &nm,Datatype *ct,const Address &cad
|
|||
{
|
||||
Symbol *sym;
|
||||
|
||||
sym = new Symbol(this,nm,ct);
|
||||
sym = new Symbol(owner,nm,ct);
|
||||
addSymbolInternal(sym);
|
||||
RangeList rnglist;
|
||||
if (!caddr.isInvalid())
|
||||
|
@ -1696,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)
|
||||
|
||||
{
|
||||
|
@ -1832,12 +1844,17 @@ list<SymbolEntry>::iterator ScopeInternal::endDynamic(void)
|
|||
/// \param nm is the name of the Scope
|
||||
/// \param g is the Architecture it belongs to
|
||||
ScopeInternal::ScopeInternal(const string &nm,Architecture *g)
|
||||
: Scope(nm,g)
|
||||
: Scope(nm,g,this)
|
||||
{
|
||||
nextUniqueId = 0;
|
||||
int4 numspaces = g->numSpaces();
|
||||
for(int4 i=0;i<numspaces;++i)
|
||||
maptable.push_back((EntryMap *)0);
|
||||
maptable.resize(g->numSpaces(),(EntryMap *)0);
|
||||
}
|
||||
|
||||
ScopeInternal::ScopeInternal(const string &nm,Architecture *g, Scope *own)
|
||||
: Scope(nm,g,own)
|
||||
{
|
||||
nextUniqueId = 0;
|
||||
maptable.resize(g->numSpaces(),(EntryMap *)0);
|
||||
}
|
||||
|
||||
ScopeInternal::~ScopeInternal(void)
|
||||
|
@ -2277,13 +2294,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);
|
||||
Symbol sym((Scope *)0,nm,(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() == nm)
|
||||
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,
|
||||
|
@ -2564,6 +2589,23 @@ void ScopeInternal::processHole(const Element *el)
|
|||
}
|
||||
}
|
||||
|
||||
/// \brief Parse a \<collision> 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 \<collision> 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.
|
||||
|
@ -2638,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;
|
||||
|
@ -2892,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
|
||||
|
@ -2926,8 +2986,8 @@ Scope *Database::resolveScope(const vector<string> &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;
|
||||
|
@ -2947,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.
|
||||
|
@ -3095,28 +3186,13 @@ void Database::restoreXml(const Element *el)
|
|||
|
||||
for(;iter!=list.end();++iter) {
|
||||
const Element *subel = *iter;
|
||||
Scope *new_scope;
|
||||
string name;
|
||||
vector<string> 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;i<parnames.size();++i) {
|
||||
Scope *nextscope = curscope->resolveScope(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;i<parnames.size();++i)
|
||||
new_scope = findCreateSubscope(parnames[i], new_scope);
|
||||
new_scope->restoreXml(subel);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -167,6 +167,8 @@ protected:
|
|||
uint2 catindex; ///< Index within category
|
||||
uint8 symbolId; ///< Unique id, 0=unassigned
|
||||
vector<list<SymbolEntry>::iterator> mapentry; ///< List of storage locations labeled with \b this Symbol
|
||||
mutable const Scope *depthScope; ///< Scope associated with current depth resolution
|
||||
mutable int4 depthResolution; ///< Number of namespace elements required to resolve symbol in current scope
|
||||
uint4 wholeCount; ///< Number of SymbolEntries that map to the whole Symbol
|
||||
virtual ~Symbol(void) {} ///< Destructor
|
||||
void setDisplayFormat(uint4 val); ///< Set the display format for \b this Symbol
|
||||
|
@ -183,13 +185,9 @@ public:
|
|||
isolate = 16, ///< Symbol should not speculatively merge automatically
|
||||
merge_problems = 32 ///< Set if some SymbolEntrys did not get merged
|
||||
};
|
||||
/// \brief Construct given a name and data-type
|
||||
Symbol(Scope *sc,const string &nm,Datatype *ct)
|
||||
{ scope=sc; name=nm; nameDedup=0; type=ct; flags=0; dispflags=0; category=-1; symbolId=0; wholeCount=0; }
|
||||
|
||||
/// \brief Construct for use with restoreXml()
|
||||
Symbol(Scope *sc) { scope=sc; nameDedup=0; flags=0; dispflags=0; category=-1; symbolId = 0; wholeCount=0; }
|
||||
|
||||
Symbol(Scope *sc,const string &nm,Datatype *ct); ///< Construct given a name and data-type
|
||||
Symbol(Scope *sc); ///< Construct for use with restoreXml()
|
||||
const string &getName(void) const { return name; } ///< Get the local name of the symbol
|
||||
Datatype *getType(void) const { return type; } ///< Get the data-type
|
||||
uint8 getId(void) const { return symbolId; } ///< Get a unique id for the symbol
|
||||
|
@ -214,7 +212,7 @@ public:
|
|||
int4 numEntries(void) const { return mapentry.size(); } ///< Return the number of SymbolEntrys
|
||||
SymbolEntry *getMapEntry(int4 i) const { return &(*mapentry[i]); } ///< Return the i-th SymbolEntry for \b this Symbol
|
||||
int4 getMapEntryPosition(const SymbolEntry *entry) const; ///< Position of given SymbolEntry within \b this multi-entry Symbol
|
||||
int4 getResolutionDepth(const Scope *useScope) const; ///< Get the number of scope names to print to resolve symbol in given context
|
||||
int4 getResolutionDepth(const Scope *useScope) const; ///< Get number of scope names needed to resolve \b this symbol
|
||||
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
|
||||
|
@ -415,11 +413,11 @@ class Scope {
|
|||
friend class ScopeCompare;
|
||||
RangeList rangetree; ///< Range of data addresses \e owned by \b this scope
|
||||
Scope *parent; ///< The parent scope
|
||||
Scope *owner; ///< Scope using \b this as a cache
|
||||
ScopeMap children; ///< Sorted list of child scopes
|
||||
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
|
||||
|
@ -454,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
|
||||
|
@ -493,7 +500,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
|
||||
|
@ -502,8 +509,8 @@ public:
|
|||
void turnOffDebug(void) const { debugon = false; }
|
||||
#endif
|
||||
/// \brief Construct an empty scope, given a name and Architecture
|
||||
Scope(const string &nm,Architecture *g) {
|
||||
name = nm; glb = g; parent = (Scope *)0; fd = (Funcdata *)0; uniqueId = 0;
|
||||
Scope(const string &nm,Architecture *g,Scope *own) {
|
||||
name = nm; glb = g; parent = (Scope *)0; fd = (Funcdata *)0; uniqueId = 0; owner=own;
|
||||
#ifdef OPACTION_DEBUG
|
||||
debugon = false;
|
||||
#endif
|
||||
|
@ -604,13 +611,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,8 +702,7 @@ 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<string> &vec) const; ///< Get the fullname of \b this in segments
|
||||
void getScopePath(vector<Scope *> &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
|
||||
void getScopePath(vector<const Scope *> &vec) const; ///< Get the ordered list of scopes up to \b this
|
||||
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)
|
||||
|
@ -720,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,
|
||||
|
@ -735,6 +744,7 @@ protected:
|
|||
uint8 nextUniqueId; ///< Next available symbol id
|
||||
public:
|
||||
ScopeInternal(const string &nm,Architecture *g); ///< Construct the Scope
|
||||
ScopeInternal(const string &nm,Architecture *g, Scope *own); ///< Construct as a cache
|
||||
virtual void clear(void);
|
||||
virtual void categorySanity(void); ///< Make sure Symbol categories are sane
|
||||
virtual void clearCategory(int4 cat);
|
||||
|
@ -766,7 +776,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,
|
||||
|
@ -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<string> &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
|
||||
|
@ -870,4 +882,41 @@ public:
|
|||
void restoreXmlScope(const Element *el,Scope *new_scope); ///< Register and fill out a single Scope from XML
|
||||
};
|
||||
|
||||
/// \param sc is the scope containing the new symbol
|
||||
/// \param nm is the local name of the symbol
|
||||
/// \param ct is the data-type of the symbol
|
||||
inline Symbol::Symbol(Scope *sc,const string &nm,Datatype *ct)
|
||||
|
||||
{
|
||||
scope=sc;
|
||||
name=nm;
|
||||
nameDedup=0;
|
||||
type=ct;
|
||||
flags=0;
|
||||
dispflags=0;
|
||||
category=-1;
|
||||
catindex = 0;
|
||||
symbolId=0;
|
||||
wholeCount=0;
|
||||
depthScope = (const Scope *)0;
|
||||
depthResolution = 0;
|
||||
}
|
||||
|
||||
/// \param sc is the scope containing the new symbol
|
||||
inline Symbol::Symbol(Scope *sc)
|
||||
|
||||
{
|
||||
scope=sc;
|
||||
nameDedup=0;
|
||||
type = (Datatype *)0;
|
||||
flags=0;
|
||||
dispflags=0;
|
||||
category=-1;
|
||||
catindex = 0;
|
||||
symbolId = 0;
|
||||
wholeCount=0;
|
||||
depthScope = (const Scope *)0;
|
||||
depthResolution = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -16,12 +16,18 @@
|
|||
#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)
|
||||
: Scope("",g,this)
|
||||
{
|
||||
ghidra = g;
|
||||
cache = new ScopeInternal("",g);
|
||||
cache = new ScopeInternal("",g,this);
|
||||
cacheDirty = false;
|
||||
}
|
||||
|
||||
|
@ -31,50 +37,51 @@ 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 par is the parent Scope
|
||||
/// \return the new \e namespace Scope
|
||||
Scope *ScopeGhidra::createNewScope(const string &nm,Scope *par) const
|
||||
|
||||
{
|
||||
Scope *newscope = new ScopeGhidraNamespace(nm,ghidra);
|
||||
ghidra->symboltab->attachScope(newscope,par);
|
||||
// Document *doc = ghidra->getScopeProperties(newscope);
|
||||
// if (doc == (Document *)0)
|
||||
// throw LowlevelError("Bad getScopeProperties response");
|
||||
// const Element *root = doc->getRoot();
|
||||
// if (root->getName() == "rangelist") {
|
||||
// RangeList newrangetree;
|
||||
// newrangetree.restoreXml(root,ghidra);
|
||||
// ghidra->symboltab->set_range(newscope,newrangetree);
|
||||
// }
|
||||
// delete doc;
|
||||
return newscope;
|
||||
}
|
||||
|
||||
/// The Ghidra client reports a \e namespace path associated with
|
||||
/// Symbol. Determine if this Scope already exists in the cache and built
|
||||
/// 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.
|
||||
/// \param path is absolute path to the desired Scope
|
||||
/// \return the Scope matching the path.
|
||||
Scope *ScopeGhidra::reresolveScope(const vector<string> &path) const
|
||||
/// \param id is the ID associated with the Ghidra namespace
|
||||
/// \return the Scope matching the id.
|
||||
Scope *ScopeGhidra::reresolveScope(uint8 id) const
|
||||
|
||||
{
|
||||
if (path.size()==1) return cache;
|
||||
// Get pointer to ourselves (which is not const)
|
||||
Scope *curscope = glb->symboltab->getGlobalScope();
|
||||
int4 i;
|
||||
for(i=1;i<path.size();++i) {
|
||||
Scope *nextscope = curscope->resolveScope(path[i]);
|
||||
if (nextscope == (Scope *)0) break;
|
||||
curscope = nextscope;
|
||||
if (id == 0) return cache;
|
||||
map<uint8,Scope *>::const_iterator miter = namespaceMap.find(id);
|
||||
if (miter != namespaceMap.end())
|
||||
return (*miter).second; // Scope was previously cached
|
||||
|
||||
Document *doc = ghidra->getNamespacePath(id);
|
||||
if (doc == (Document *)0)
|
||||
throw LowlevelError("Could not get namespace info");
|
||||
|
||||
Scope *curscope = glb->symboltab->getGlobalScope(); // Get pointer to ourselves (which is not const)
|
||||
try {
|
||||
const List &list(doc->getRoot()->getChildren());
|
||||
List::const_iterator iter = list.begin();
|
||||
++iter; // Skip element describing the root scope
|
||||
while(iter != list.end()) {
|
||||
const Element *el = *iter;
|
||||
++iter;
|
||||
uint8 scopeId;
|
||||
istringstream s(el->getAttributeValue("id"));
|
||||
s.unsetf(ios::dec | ios::hex | ios::oct);
|
||||
s >> scopeId;
|
||||
miter = namespaceMap.find(scopeId);
|
||||
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;
|
||||
}
|
||||
delete doc;
|
||||
}
|
||||
while(i != path.size()) {
|
||||
curscope = createNewScope(path[i],curscope);
|
||||
i += 1;
|
||||
catch(LowlevelError &err) {
|
||||
delete doc;
|
||||
throw err;
|
||||
}
|
||||
return curscope;
|
||||
}
|
||||
|
@ -126,16 +133,14 @@ Symbol *ScopeGhidra::dump2Cache(Document *doc) const
|
|||
}
|
||||
|
||||
List::const_iterator iter = el->getChildren().begin();
|
||||
// The first subnode must be scope information
|
||||
el = *iter;
|
||||
vector<string> path;
|
||||
const List &list2(el->getChildren());
|
||||
List::const_iterator iter2;
|
||||
for(iter2=list2.begin();iter2!=list2.end();++iter2)
|
||||
path.push_back( (*iter2)->getContent() );
|
||||
uint8 scopeId;
|
||||
{
|
||||
istringstream s(el->getAttributeValue("id"));
|
||||
s.unsetf(ios::dec | ios::hex | ios::oct);
|
||||
s >> scopeId;
|
||||
}
|
||||
|
||||
Scope *scope = reresolveScope(path);
|
||||
++iter; // The second part is a <mapsym>
|
||||
Scope *scope = reresolveScope(scopeId);
|
||||
el = *iter;
|
||||
try {
|
||||
sym = scope->addMapSym(el);
|
||||
|
@ -255,6 +260,7 @@ void ScopeGhidra::clear(void)
|
|||
{
|
||||
cache->clear();
|
||||
holes.clear();
|
||||
namespaceMap.clear();
|
||||
if (cacheDirty) {
|
||||
ghidra->symboltab->setProperties(flagbaseDefault); // Restore database properties to defaults
|
||||
cacheDirty = false;
|
||||
|
@ -402,3 +408,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->getClientId() : 0;
|
||||
return ghidra->isNameUsed(nm, scopeId, otherId);
|
||||
}
|
||||
|
|
|
@ -36,18 +36,19 @@ class ScopeGhidra : public Scope {
|
|||
ArchitectureGhidra *ghidra; ///< Architecture and connection to the Ghidra client
|
||||
mutable ScopeInternal *cache; ///< An internal cache of previously fetched Symbol objects
|
||||
mutable RangeList holes; ///< List of (queried) memory ranges with no Symbol in them
|
||||
mutable map<uint8,Scope *> namespaceMap; ///< Map from id to formal global namespace objects
|
||||
vector<int4> spacerange; ///< List of address spaces that are in the global range
|
||||
partmap<Address,uint4> flagbaseDefault; ///< Default boolean properties on memory
|
||||
mutable bool cacheDirty; ///< Is flagbaseDefault different from cache
|
||||
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,Scope *par) const; ///< Create a global \e namespace Scope
|
||||
Scope *reresolveScope(const vector<string> &path) const; ///< Find the Scope that will contain a result Symbol
|
||||
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"); }
|
||||
|
@ -89,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"); }
|
||||
|
@ -124,11 +125,19 @@ 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,Architecture *g)
|
||||
: ScopeInternal(nm,g) {} ///< Constructor
|
||||
ScopeGhidraNamespace(const string &nm,ArchitectureGhidra *g)
|
||||
: ScopeInternal(nm,g) { ghidra = g; scopeId = 0; } ///< Constructor
|
||||
|
||||
uint8 getClientId(void) const { return scopeId; } ///< Get the Ghidra specific id
|
||||
virtual bool isNameUsed(const string &nm,const Scope *op2) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -71,6 +71,7 @@ FloatFormat::FloatFormat(int4 sz)
|
|||
jbitimplied = true;
|
||||
}
|
||||
maxexponent = (1<<exp_size)-1;
|
||||
calcPrecision();
|
||||
}
|
||||
|
||||
/// \param sign is set to \b true if the value should be negative
|
||||
|
@ -227,6 +228,13 @@ uintb FloatFormat::getNaNEncoding(bool sgn) const
|
|||
return setSign(res,sgn);
|
||||
}
|
||||
|
||||
void FloatFormat::calcPrecision(void)
|
||||
|
||||
{
|
||||
float val = frac_size * 0.30103;
|
||||
decimal_precision = (int4)floor(val + 0.5);
|
||||
}
|
||||
|
||||
/// \param encoding is the encoding value
|
||||
/// \param type points to the floating-point class, which is passed back
|
||||
/// \return the equivalent double value
|
||||
|
@ -613,4 +621,5 @@ void FloatFormat::restoreXml(const Element *el)
|
|||
}
|
||||
jbitimplied = xml_readbool(el->getAttributeValue("jbitimplied"));
|
||||
maxexponent = (1<<exp_size)-1;
|
||||
calcPrecision();
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ private:
|
|||
int4 exp_size; ///< Number of bits in exponent
|
||||
int4 bias; ///< What to add to real exponent to get encoding
|
||||
int4 maxexponent; ///< Maximum possible exponent
|
||||
int4 decimal_precision; ///< Number of decimal digits of precision
|
||||
bool jbitimplied; ///< Set to \b true if integer bit of 1 is assumed
|
||||
static double createFloat(bool sign,uintb signif,int4 exp); ///< Create a double given sign, fractional, and exponent
|
||||
static floatclass extractExpSig(double x,bool *sgn,uintb *signif,int4 *exp);
|
||||
|
@ -55,12 +56,14 @@ private:
|
|||
uintb getZeroEncoding(bool sgn) const; ///< Get an encoded zero value
|
||||
uintb getInfinityEncoding(bool sgn) const; ///< Get an encoded infinite value
|
||||
uintb getNaNEncoding(bool sgn) const; ///< Get an encoded NaN value
|
||||
void calcPrecision(void); ///< Calculate the decimal precision of this format
|
||||
public:
|
||||
FloatFormat(void) {} ///< Construct for use with restoreXml()
|
||||
FloatFormat(int4 sz); ///< Construct default IEEE 754 standard settings
|
||||
int4 getSize(void) const { return size; } ///< Get the size of the encoding in bytes
|
||||
double getHostFloat(uintb encoding,floatclass *type) const; ///< Convert an encoding into host's double
|
||||
uintb getEncoding(double host) const; ///< Convert host's double into \b this encoding
|
||||
int4 getDecimalPrecision(void) const { return decimal_precision; } ///< Get number of digits of precision
|
||||
uintb convertEncoding(uintb encoding,const FloatFormat *formin) const; ///< Convert between two different formats
|
||||
|
||||
uintb extractFractionalCode(uintb x) const; ///< Extract the fractional part of the encoding
|
||||
|
|
|
@ -2479,7 +2479,7 @@ ProtoParameter *ProtoStoreSymbol::setInput(int4 i, const string &nm,const Parame
|
|||
}
|
||||
}
|
||||
if (res->sym == (Symbol *)0) {
|
||||
if (scope->discoverScope(pieces.addr,pieces.type->getSize(),usepoint) != scope)
|
||||
if (scope->discoverScope(pieces.addr,pieces.type->getSize(),usepoint) == (Scope *)0)
|
||||
usepoint = restricted_usepoint;
|
||||
res->sym = scope->addSymbol(nm,pieces.type,pieces.addr,usepoint)->getSymbol();
|
||||
scope->setCategory(res->sym,0,i);
|
||||
|
@ -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<Varnode *> &triallist,ParamActive *activeinput)
|
||||
void FuncProto::updateInputTypes(Funcdata &data,const vector<Varnode *> &triallist,ParamActive *activeinput)
|
||||
|
||||
{
|
||||
if (isInputLocked()) return; // Input is locked, do no updating
|
||||
|
@ -3195,15 +3196,25 @@ void FuncProto::updateInputTypes(const vector<Varnode *> &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.size();++i)
|
||||
|
@ -3215,29 +3226,36 @@ void FuncProto::updateInputTypes(const vector<Varnode *> &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<Varnode *> &triallist,ParamActive *activeinput,
|
||||
TypeFactory *factory)
|
||||
void FuncProto::updateInputNoTypes(Funcdata &data,const vector<Varnode *> &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;i<numtrials;++i) {
|
||||
ParamTrial &trial(activeinput->getTrial(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;i<triallist.size();++i)
|
||||
|
@ -4088,7 +4106,7 @@ Varnode *FuncCallSpecs::buildParam(Funcdata &data,Varnode *vn,ProtoParameter *pa
|
|||
Varnode *newout = data.newUniqueOut(param->getSize(),newop);
|
||||
// Its possible vn is free, in which case the SetInput would give it multiple descendants
|
||||
// See we construct a new version
|
||||
if (vn->isFree() && (!vn->hasNoDescend()))
|
||||
if (vn->isFree() && !vn->isConstant() && !vn->hasNoDescend())
|
||||
vn = data.newVarnode(vn->getSize(),vn->getAddr());
|
||||
data.opSetInput(newop,vn,0);
|
||||
data.opSetInput(newop,data.newConstant(4,0),1);
|
||||
|
|
|
@ -1327,8 +1327,8 @@ public:
|
|||
bool checkInputSplit(const Address &loc,int4 size,int4 splitpoint) const {
|
||||
return model->checkInputSplit(loc,size,splitpoint); }
|
||||
|
||||
void updateInputTypes(const vector<Varnode *> &triallist,ParamActive *activeinput);
|
||||
void updateInputNoTypes(const vector<Varnode *> &triallist,ParamActive *activeinput,TypeFactory *factory);
|
||||
void updateInputTypes(Funcdata &data,const vector<Varnode *> &triallist,ParamActive *activeinput);
|
||||
void updateInputNoTypes(Funcdata &data,const vector<Varnode *> &triallist,ParamActive *activeinput);
|
||||
void updateOutputTypes(const vector<Varnode *> &triallist);
|
||||
void updateOutputNoTypes(const vector<Varnode *> &triallist,TypeFactory *factory);
|
||||
void updateAllTypes(const vector<string> &namelist,const vector<Datatype *> &typelist,bool dtdtdt);
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
/// \param scope is Symbol scope associated with the function
|
||||
/// \param addr is the entry address for the function
|
||||
/// \param sz is the number of bytes (of code) in the function body
|
||||
Funcdata::Funcdata(const string &nm,Scope *scope,const Address &addr,int4 sz)
|
||||
Funcdata::Funcdata(const string &nm,Scope *scope,const Address &addr,FunctionSymbol *sym,int4 sz)
|
||||
: baseaddr(addr),
|
||||
funcp(),
|
||||
vbank(scope->getArch(),
|
||||
|
@ -31,6 +31,7 @@ Funcdata::Funcdata(const string &nm,Scope *scope,const Address &addr,int4 sz)
|
|||
|
||||
{ // Initialize high-level properties of
|
||||
// function by giving address and size
|
||||
functionSymbol = sym;
|
||||
flags = 0;
|
||||
clean_up_index = 0;
|
||||
high_level_index = 0;
|
||||
|
|
|
@ -63,9 +63,10 @@ class Funcdata {
|
|||
uint4 high_level_index; ///< Creation index of first Varnode created after HighVariables are created
|
||||
uint4 cast_phase_index; ///< Creation index of first Varnode created after ActionSetCasts
|
||||
uint4 minLanedSize; ///< Minimum Varnode size to check as LanedRegister
|
||||
Architecture *glb; ///< Global configuration data
|
||||
string name; ///< Name of function
|
||||
int4 size; ///< Number of bytes of binary data in function body
|
||||
Architecture *glb; ///< Global configuration data
|
||||
FunctionSymbol *functionSymbol; ///< The symbol representing \b this function
|
||||
string name; ///< Name of function
|
||||
Address baseaddr; ///< Starting code address of binary data
|
||||
FuncProto funcp; ///< Prototype of this function
|
||||
ScopeLocal *localmap; ///< Local variables (symbols in the function scope)
|
||||
|
@ -119,12 +120,13 @@ class Funcdata {
|
|||
static PcodeOp *findPrimaryBranch(PcodeOpTree::const_iterator iter,PcodeOpTree::const_iterator enditer,
|
||||
bool findbranch,bool findcall,bool findreturn);
|
||||
public:
|
||||
Funcdata(const string &nm,Scope *conf,const Address &addr,int4 sz=0); ///< Constructor
|
||||
Funcdata(const string &nm,Scope *conf,const Address &addr,FunctionSymbol *sym,int4 sz=0); ///< Constructor
|
||||
~Funcdata(void); ///< Destructor
|
||||
const string &getName(void) const { return name; } ///< Get the function's local symbol name
|
||||
const Address &getAddress(void) const { return baseaddr; } ///< Get the entry point address
|
||||
int4 getSize(void) const { return size; } ///< Get the function body size in bytes
|
||||
Architecture *getArch(void) const { return glb; } ///< Get the program/architecture owning the function
|
||||
Architecture *getArch(void) const { return glb; } ///< Get the program/architecture owning \b this function
|
||||
FunctionSymbol *getSymbol(void) const { return functionSymbol; } ///< Return the symbol associated with \b this function
|
||||
bool isHighOn(void) const { return ((flags&highlevel_on)!=0); } ///< Are high-level variables assigned to Varnodes
|
||||
bool isProcStarted(void) const { return ((flags&processing_started)!=0); } ///< Has processing of the function started
|
||||
bool isProcComplete(void) const { return ((flags&processing_complete)!=0); } ///< Is processing of the function complete
|
||||
|
@ -264,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
|
||||
|
|
|
@ -495,7 +495,7 @@ int4 Funcdata::stageJumpTable(JumpTable *jt,PcodeOp *op,FlowInfo *flow)
|
|||
s1 << name << "@@jump@";
|
||||
op->getAddr().printRaw(s1);
|
||||
|
||||
Funcdata partial(s1.str(),localmap->getParent(),baseaddr);
|
||||
Funcdata partial(s1.str(),localmap->getParent(),baseaddr,(FunctionSymbol *)0);
|
||||
partial.flags |= jumptablerecovery_on; // Mark that this Funcdata object is dedicated to jumptable recovery
|
||||
partial.truncatedFlow(this,flow);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
@ -1326,6 +1355,7 @@ void Funcdata::mapGlobals(void)
|
|||
vn = *iter++;
|
||||
if (vn->isFree()) continue;
|
||||
if (!vn->isPersist()) continue; // Could be a code ref
|
||||
if (vn->getSymbolEntry() != (SymbolEntry *)0) continue;
|
||||
maxvn = vn;
|
||||
Address addr = vn->getAddr();
|
||||
Address endaddr = addr + vn->getSize();
|
||||
|
|
|
@ -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.
|
||||
|
@ -515,6 +543,48 @@ Document *ArchitectureGhidra::getExternalRefXML(const Address &addr)
|
|||
return readXMLAll(sin);
|
||||
}
|
||||
|
||||
/// Ask the Ghidra client to list all namespace elements between the global root
|
||||
/// and the namespace of the given id. The client should return a \<parent> tag with
|
||||
/// a \<val> child for each namespace in the path.
|
||||
/// \param id is the given id of the namespace to resolve
|
||||
/// \return the XML document
|
||||
Document *ArchitectureGhidra::getNamespacePath(uint8 id)
|
||||
|
||||
{
|
||||
sout.write("\000\000\001\004",4);
|
||||
writeStringStream(sout,"getNamespacePath");
|
||||
sout.write("\000\000\001\016",4); // Beginning of string header
|
||||
sout << hex << id;
|
||||
sout.write("\000\000\001\017",4);
|
||||
sout.write("\000\000\001\005",4);
|
||||
sout.flush();
|
||||
|
||||
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
|
||||
|
@ -772,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -92,6 +92,8 @@ public:
|
|||
uint1 *getPcodePacked(const Address &addr); ///< Get p-code for a single instruction
|
||||
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
|
||||
|
@ -130,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
|
||||
|
@ -139,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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<Address,SizePass>::const_iterator iter = themap.upper_bound(addr); // First range after address
|
||||
|
|
|
@ -47,12 +47,12 @@ private:
|
|||
map<Address,SizePass> 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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -81,6 +81,7 @@ OptionDatabase::OptionDatabase(Architecture *g)
|
|||
registerOption(new OptionToggleRule());
|
||||
registerOption(new OptionAliasBlock());
|
||||
registerOption(new OptionMaxInstruction());
|
||||
registerOption(new OptionNamespaceStrategy());
|
||||
}
|
||||
|
||||
OptionDatabase::~OptionDatabase(void)
|
||||
|
@ -833,3 +834,23 @@ string OptionMaxInstruction::apply(Architecture *glb,const string &p1,const stri
|
|||
glb->max_instructions = newMax;
|
||||
return "Maximum instructions per function set";
|
||||
}
|
||||
|
||||
/// \class OptionNamespaceStrategy
|
||||
/// \brief How should namespace tokens be displayed
|
||||
///
|
||||
/// The first parameter gives the strategy identifier, mapping to PrintLanguage::namespace_strategy.
|
||||
string OptionNamespaceStrategy::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const
|
||||
|
||||
{
|
||||
PrintLanguage::namespace_strategy strategy;
|
||||
if (p1 == "minimal")
|
||||
strategy = PrintLanguage::MINIMAL_NAMESPACES;
|
||||
else if (p1 == "all")
|
||||
strategy = PrintLanguage::ALL_NAMESPACES;
|
||||
else if (p1 == "none")
|
||||
strategy = PrintLanguage::NO_NAMESPACES;
|
||||
else
|
||||
throw ParseError("Must specify a valid strategy");
|
||||
glb->print->setNamespaceStrategy(strategy);
|
||||
return "Namespace strategy set";
|
||||
}
|
||||
|
|
|
@ -270,4 +270,10 @@ public:
|
|||
virtual string apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const;
|
||||
};
|
||||
|
||||
class OptionNamespaceStrategy : public ArchOption {
|
||||
public:
|
||||
OptionNamespaceStrategy(void) { name = "namespacestrategy"; } ///< Constructor
|
||||
virtual string apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -38,6 +38,7 @@ OpToken PrintC::binary_plus = { "+", 2, 50, true, OpToken::binary, 1, 0, (OpToke
|
|||
OpToken PrintC::binary_minus = { "-", 2, 50, false, OpToken::binary, 1, 0, (OpToken *)0 };
|
||||
OpToken PrintC::shift_left = { "<<", 2, 46, false, OpToken::binary, 1, 0, (OpToken *)0 };
|
||||
OpToken PrintC::shift_right = { ">>", 2, 46, false, OpToken::binary, 1, 0, (OpToken *)0 };
|
||||
OpToken PrintC::shift_sright = { ">>", 2, 46, false, OpToken::binary, 1, 0, (OpToken *)0 };
|
||||
OpToken PrintC::less_than = { "<", 2, 42, false, OpToken::binary, 1, 0, (OpToken *)0 };
|
||||
OpToken PrintC::less_equal = { "<=", 2, 42, false, OpToken::binary, 1, 0, (OpToken *)0 };
|
||||
OpToken PrintC::greater_than = { ">", 2, 42, false, OpToken::binary, 1, 0, (OpToken *)0 };
|
||||
|
@ -167,6 +168,68 @@ void PrintC::pushPrototypeInputs(const FuncProto *proto)
|
|||
}
|
||||
}
|
||||
|
||||
/// Calculate what elements of a given symbol's namespace path are necessary to distinguish
|
||||
/// it within the current scope. Then print these elements.
|
||||
/// \param symbol is the given symbol
|
||||
void PrintC::pushSymbolScope(const Symbol *symbol)
|
||||
|
||||
{
|
||||
int4 scopedepth;
|
||||
if (namespc_strategy == MINIMAL_NAMESPACES)
|
||||
scopedepth = symbol->getResolutionDepth(curscope);
|
||||
else if (namespc_strategy == ALL_NAMESPACES) {
|
||||
if (symbol->getScope() == curscope)
|
||||
scopedepth = 0;
|
||||
else
|
||||
scopedepth = symbol->getResolutionDepth((const Scope *)0);
|
||||
}
|
||||
else
|
||||
scopedepth = 0;
|
||||
if (scopedepth != 0) {
|
||||
vector<const Scope *> scopeList;
|
||||
const Scope *point = symbol->getScope();
|
||||
for(int4 i=0;i<scopedepth;++i) {
|
||||
scopeList.push_back(point);
|
||||
point = point->getParent();
|
||||
pushOp(&scope, (PcodeOp *)0);
|
||||
}
|
||||
for(int4 i=scopedepth-1;i>=0;--i) {
|
||||
pushAtom(Atom(scopeList[i]->getName(),syntax,EmitXml::global_color,(PcodeOp *)0,(Varnode *)0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit the elements of the given function's namespace path that distinguish it within
|
||||
/// the current scope.
|
||||
/// \param fd is the given function
|
||||
void PrintC::emitSymbolScope(const Symbol *symbol)
|
||||
|
||||
{
|
||||
int4 scopedepth;
|
||||
if (namespc_strategy == MINIMAL_NAMESPACES)
|
||||
scopedepth = symbol->getResolutionDepth(curscope);
|
||||
else if (namespc_strategy == ALL_NAMESPACES) {
|
||||
if (symbol->getScope() == curscope)
|
||||
scopedepth = 0;
|
||||
else
|
||||
scopedepth = symbol->getResolutionDepth((const Scope *)0);
|
||||
}
|
||||
else
|
||||
scopedepth = 0;
|
||||
if (scopedepth != 0) {
|
||||
vector<const Scope *> scopeList;
|
||||
const Scope *point = symbol->getScope();
|
||||
for(int4 i=0;i<scopedepth;++i) {
|
||||
scopeList.push_back(point);
|
||||
point = point->getParent();
|
||||
}
|
||||
for(int4 i=scopedepth-1;i>=0;--i) {
|
||||
emit->print(scopeList[i]->getName().c_str(), EmitXml::global_color);
|
||||
emit->print(scope.print, EmitXml::no_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Store off array sizes for printing after the identifier
|
||||
/// \param ct is the data-type to push
|
||||
/// \param noident is \b true if an identifier will not be pushed as part of the declaration
|
||||
|
@ -453,8 +516,12 @@ void PrintC::opCall(const PcodeOp *op)
|
|||
string name = genericFunctionName(fc->getEntryAddress());
|
||||
pushAtom(Atom(name,functoken,EmitXml::funcname_color,op,(const Funcdata *)0));
|
||||
}
|
||||
else
|
||||
else {
|
||||
Funcdata *fd = fc->getFuncdata();
|
||||
if (fd != (Funcdata *)0)
|
||||
pushSymbolScope(fd->getSymbol());
|
||||
pushAtom(Atom(fc->getName(),functoken,EmitXml::funcname_color,op,(const Funcdata *)0));
|
||||
}
|
||||
}
|
||||
else {
|
||||
clear();
|
||||
|
@ -718,8 +785,10 @@ void PrintC::opPtrsub(const PcodeOp *op)
|
|||
int4 newoff;
|
||||
const TypeField *fld = ((TypeStruct *)ct)->getField((int4)suboff,0,&newoff);
|
||||
if (fld == (const TypeField *)0) {
|
||||
if (ct->getSize() <= suboff)
|
||||
if (ct->getSize() <= suboff) {
|
||||
clear();
|
||||
throw LowlevelError("PTRSUB out of bounds into struct");
|
||||
}
|
||||
// Try to match the Ghidra's default field name from DataTypeComponent.getDefaultFieldName
|
||||
ostringstream s;
|
||||
s << "field_0x" << hex << suboff;
|
||||
|
@ -1087,38 +1156,59 @@ void PrintC::push_integer(uintb val,int4 sz,bool sign,
|
|||
/// \param op is the PcodeOp using the value
|
||||
void PrintC::push_float(uintb val,int4 sz,const Varnode *vn,const PcodeOp *op)
|
||||
{
|
||||
ostringstream t;
|
||||
string token;
|
||||
|
||||
const FloatFormat *format = glb->translate->getFloatFormat(sz);
|
||||
if (format == (const FloatFormat *)0) {
|
||||
t << "FLOAT_UNKNOWN";
|
||||
token = "FLOAT_UNKNOWN";
|
||||
}
|
||||
else {
|
||||
FloatFormat::floatclass type;
|
||||
double floatval = format->getHostFloat(val,&type);
|
||||
if (type == FloatFormat::infinity) {
|
||||
if (format->extractSign(val))
|
||||
t << '-';
|
||||
t << "INFINITY";
|
||||
token = "-INFINITY";
|
||||
else
|
||||
token = "INFINITY";
|
||||
}
|
||||
else if (type == FloatFormat::nan) {
|
||||
if (format->extractSign(val))
|
||||
t << '-';
|
||||
t << "NAN";
|
||||
token = "-NAN";
|
||||
else
|
||||
token = "NAN";
|
||||
}
|
||||
else {
|
||||
if ((mods & force_scinote)!=0)
|
||||
ostringstream t;
|
||||
if ((mods & force_scinote)!=0) {
|
||||
t.setf( ios::scientific ); // Set to scientific notation
|
||||
else
|
||||
t.setf( ios::fixed ); // Otherwise use fixed notation
|
||||
t.precision(8); // Number of digits of precision
|
||||
t << floatval;
|
||||
t.precision(format->getDecimalPrecision()-1);
|
||||
t << floatval;
|
||||
token = t.str();
|
||||
}
|
||||
else {
|
||||
// Try to print "minimal" accurate representation of the float
|
||||
t.unsetf( ios::floatfield ); // Use "default" notation
|
||||
t.precision(format->getDecimalPrecision());
|
||||
t << floatval;
|
||||
token = t.str();
|
||||
bool looksLikeFloat = false;
|
||||
for(int4 i=0;i<token.size();++i) {
|
||||
char c = token[i];
|
||||
if (c == '.' || c == 'e') {
|
||||
looksLikeFloat = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!looksLikeFloat) {
|
||||
token += ".0"; // Force token to look like a floating-point value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (vn==(const Varnode *)0)
|
||||
pushAtom(Atom(t.str(),syntax,EmitXml::const_color,op));
|
||||
pushAtom(Atom(token,syntax,EmitXml::const_color,op));
|
||||
else
|
||||
pushAtom(Atom(t.str(),vartoken,EmitXml::const_color,op,vn));
|
||||
pushAtom(Atom(token,vartoken,EmitXml::const_color,op,vn));
|
||||
}
|
||||
|
||||
void PrintC::printUnicode(ostream &s,int4 onechar) const
|
||||
|
@ -1556,7 +1646,7 @@ void PrintC::pushSymbol(const Symbol *sym,const Varnode *vn,const PcodeOp *op)
|
|||
tokenColor = EmitXml::param_color;
|
||||
else
|
||||
tokenColor = EmitXml::var_color;
|
||||
// FIXME: resolve scopes
|
||||
pushSymbolScope(sym);
|
||||
if (sym->hasMergeProblems() && vn != (Varnode *)0) {
|
||||
HighVariable *high = vn->getHigh();
|
||||
if (high->isUnmerged()) {
|
||||
|
@ -1913,6 +2003,8 @@ void PrintC::resetDefaults(void)
|
|||
void PrintC::adjustTypeOperators(void)
|
||||
|
||||
{
|
||||
scope.print = "::";
|
||||
shift_right.print = ">>";
|
||||
TypeOp::selectJavaOperators(glb->inst,false);
|
||||
}
|
||||
|
||||
|
@ -2158,12 +2250,14 @@ void PrintC::emitFunctionDeclaration(const Funcdata *fd)
|
|||
}
|
||||
}
|
||||
int4 id1 = emit->openGroup();
|
||||
emitSymbolScope(fd->getSymbol());
|
||||
emit->tagFuncName(fd->getName().c_str(),EmitXml::funcname_color,
|
||||
fd,(PcodeOp *)0);
|
||||
|
||||
emit->spaces(function_call.spacing,function_call.bump);
|
||||
int4 id2 = emit->openParen('(');
|
||||
emit->spaces(0,function_call.bump);
|
||||
pushScope(fd->getScopeLocal()); // Enter the function's scope for parameters
|
||||
emitPrototypeInputs(proto);
|
||||
emit->closeParen(')',id2);
|
||||
emit->closeGroup(id1);
|
||||
|
@ -2220,7 +2314,7 @@ void PrintC::docFunction(const Funcdata *fd)
|
|||
int4 id1 = emit->beginFunction(fd);
|
||||
emitCommentFuncHeader(fd);
|
||||
emit->tagLine();
|
||||
emitFunctionDeclaration(fd);
|
||||
emitFunctionDeclaration(fd); // Causes us to enter function's scope
|
||||
emit->tagLine();
|
||||
emit->tagLine();
|
||||
int4 id = emit->startIndent();
|
||||
|
@ -2230,6 +2324,7 @@ void PrintC::docFunction(const Funcdata *fd)
|
|||
emitBlockGraph(&fd->getBasicBlocks());
|
||||
else
|
||||
emitBlockGraph(&fd->getStructure());
|
||||
popScope(); // Exit function's scope
|
||||
emit->stopIndent(id);
|
||||
emit->tagLine();
|
||||
emit->print("}");
|
||||
|
|
|
@ -82,6 +82,7 @@ protected:
|
|||
static OpToken binary_minus; ///< The \e binary \e subtraction operator
|
||||
static OpToken shift_left; ///< The \e left \e shift operator
|
||||
static OpToken shift_right; ///< The \e right \e shift operator
|
||||
static OpToken shift_sright; ///< The signed \e right \e shift operator
|
||||
static OpToken less_than; ///< The \e less \e than operator
|
||||
static OpToken less_equal; ///< The \e less \e than \e or \e equal operator
|
||||
static OpToken greater_than; ///< The \e greater \e than operator
|
||||
|
@ -124,6 +125,8 @@ protected:
|
|||
// Routines that are specific to C/C++
|
||||
void buildTypeStack(const Datatype *ct,vector<const Datatype *> &typestack); ///< Prepare to push components of a data-type declaration
|
||||
void pushPrototypeInputs(const FuncProto *proto); ///< Push input parameters
|
||||
void pushSymbolScope(const Symbol *symbol); ///< Push tokens resolving a symbol's scope
|
||||
void emitSymbolScope(const Symbol *symbol); ///< Emit tokens resolving a symbol's scope
|
||||
virtual void pushTypeStart(const Datatype *ct,bool noident); ///< Push part of a data-type declaration onto the RPN stack, up to the identifier
|
||||
virtual void pushTypeEnd(const Datatype *ct); ///< Push the tail ends of a data-type declaration onto the RPN stack
|
||||
void pushBoolConstant(uintb val,const TypeBase *ct,const Varnode *vn,
|
||||
|
@ -251,7 +254,7 @@ public:
|
|||
virtual void opIntOr(const PcodeOp *op) { opBinary(&bitwise_or,op); }
|
||||
virtual void opIntLeft(const PcodeOp *op) { opBinary(&shift_left,op); }
|
||||
virtual void opIntRight(const PcodeOp *op) { opBinary(&shift_right,op); }
|
||||
virtual void opIntSright(const PcodeOp *op) { opBinary(&shift_right,op); }
|
||||
virtual void opIntSright(const PcodeOp *op) { opBinary(&shift_sright,op); }
|
||||
virtual void opIntMult(const PcodeOp *op) { opBinary(&multiply,op); }
|
||||
virtual void opIntDiv(const PcodeOp *op) { opBinary(÷,op); }
|
||||
virtual void opIntSdiv(const PcodeOp *op) { opBinary(÷,op); }
|
||||
|
|
|
@ -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.
|
||||
|
@ -99,6 +113,8 @@ void PrintJava::pushTypeEnd(const Datatype *ct)
|
|||
void PrintJava::adjustTypeOperators(void)
|
||||
|
||||
{
|
||||
scope.print = ".";
|
||||
shift_right.print = ">>>";
|
||||
TypeOp::selectJavaOperators(glb->inst,true);
|
||||
}
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -105,6 +105,16 @@ void PrintLanguage::setCommentDelimeter(const string &start,const string &stop,b
|
|||
}
|
||||
}
|
||||
|
||||
void PrintLanguage::popScope(void)
|
||||
|
||||
{
|
||||
scopestack.pop_back();
|
||||
if (scopestack.empty())
|
||||
curscope = (Scope *)0;
|
||||
else
|
||||
curscope = scopestack.back();
|
||||
}
|
||||
|
||||
/// This generally will recursively push an entire expression onto the RPN stack,
|
||||
/// up to Varnode objects marked as \e explicit, and will decide token order
|
||||
/// and parenthesis placement. As the ordering gets resolved,
|
||||
|
@ -565,6 +575,7 @@ void PrintLanguage::resetDefaultsInternal(void)
|
|||
mods = 0;
|
||||
head_comment_type = Comment::header | Comment::warningheader;
|
||||
line_commentindent = 20;
|
||||
namespc_strategy = MINIMAL_NAMESPACES;
|
||||
instr_comment_type = Comment::user2 | Comment::warning;
|
||||
}
|
||||
|
||||
|
@ -658,10 +669,8 @@ void PrintLanguage::clear(void)
|
|||
mods = modstack.front();
|
||||
modstack.clear();
|
||||
}
|
||||
if (!scopestack.empty()) {
|
||||
curscope = scopestack.front();
|
||||
scopestack.clear();
|
||||
}
|
||||
scopestack.clear();
|
||||
curscope = (const Scope *)0;
|
||||
revpol.clear();
|
||||
pending = 0;
|
||||
|
||||
|
|
|
@ -162,6 +162,13 @@ public:
|
|||
blanktoken ///< For anonymous types
|
||||
};
|
||||
|
||||
/// \brief Strategies for displaying namespace tokens
|
||||
enum namespace_strategy {
|
||||
MINIMAL_NAMESPACES = 0, ///< (default) Print just enough namespace info to fully resolve symbol
|
||||
NO_NAMESPACES = 1, ///< Never print namespace information
|
||||
ALL_NAMESPACES = 2 ///< Always print all namespace information
|
||||
};
|
||||
|
||||
/// \brief An entry on the reverse polish notation (RPN) stack
|
||||
struct ReversePolish {
|
||||
const OpToken *tok; ///< The operator token
|
||||
|
@ -230,8 +237,7 @@ public:
|
|||
private:
|
||||
string name; ///< The name of the high-level language
|
||||
vector<uint4> modstack; ///< Printing modification stack
|
||||
vector<Scope *> scopestack; ///< The symbol scope stack
|
||||
Scope *curscope; ///< The current symbol scope
|
||||
vector<const Scope *> scopestack; ///< The symbol scope stack
|
||||
vector<ReversePolish> revpol; ///< The Reverse Polish Notation (RPN) token stack
|
||||
vector<NodePending> nodepend; ///< Data-flow nodes waiting to be pushed onto the RPN stack
|
||||
int4 pending; ///< Number of data-flow nodes waiting to be pushed
|
||||
|
@ -240,19 +246,21 @@ private:
|
|||
string commentend; ///< Delimiter characters (if any) for the end of a comment
|
||||
protected:
|
||||
Architecture *glb; ///< The Architecture owning the language emitter
|
||||
const Scope *curscope; ///< The current symbol scope
|
||||
CastStrategy *castStrategy; ///< The strategy for emitting explicit \e case operations
|
||||
EmitXml *emit; ///< The low-level token emitter
|
||||
uint4 mods; ///< Currently active printing modifications
|
||||
uint4 instr_comment_type; ///< Type of instruction comments to display
|
||||
uint4 head_comment_type; ///< Type of header comments to display
|
||||
namespace_strategy namespc_strategy; ///< How should namespace tokens be displayed
|
||||
#ifdef CPUI_DEBUG
|
||||
bool isStackEmpty(void) const { return (nodepend.empty()&&revpol.empty()); } ///< Return \b true if the RPN stack is empty
|
||||
bool isModStackEmpty(void) const { return modstack.empty(); } ///< Return \b true if the printing modification stack is empty
|
||||
#endif
|
||||
// Routines that are probably consistent across languages
|
||||
bool isSet(uint4 m) const { return ((mods & m)!=0); } ///< Is the given printing modification active
|
||||
void pushScope(Scope *sc) { scopestack.push_back(sc); curscope = sc; } ///< Push a new symbol scope
|
||||
void popScope(void) { scopestack.pop_back(); curscope = scopestack.back(); } ///< Pop to the previous symbol scope
|
||||
void pushScope(const Scope *sc) { scopestack.push_back(sc); curscope = sc; } ///< Push a new symbol scope
|
||||
void popScope(void); ///< Pop to the previous symbol scope
|
||||
void pushMod(void) { modstack.push_back(mods); } ///< Push current printing modifications to the stack
|
||||
void popMod(void) { mods = modstack.back(); modstack.pop_back(); } ///< Pop to the previous printing modifications
|
||||
void setMod(uint4 m) { mods |= m; } ///< Activate the given printing modification
|
||||
|
@ -405,7 +413,6 @@ public:
|
|||
CastStrategy *getCastStrategy(void) const { return castStrategy; } ///< Get the casting strategy for the language
|
||||
ostream *getOutputStream(void) const { return emit->getOutputStream(); } ///< Get the output stream being emitted to
|
||||
void setOutputStream(ostream *t) { emit->setOutputStream(t); } ///< Set the output stream to emit to
|
||||
void setScope(Scope *sc) { curscope = sc; } ///< Set the current Symbol scope
|
||||
void setMaxLineSize(int4 mls) { emit->setMaxLineSize(mls); } ///< Set the maximum number of characters per line
|
||||
void setIndentIncrement(int4 inc) { emit->setIndentIncrement(inc); } ///< Set the number of characters to indent per level of code nesting
|
||||
void setLineCommentIndent(int4 val); ///< Set the number of characters to indent comment lines
|
||||
|
@ -413,6 +420,7 @@ public:
|
|||
bool usecommentfill); ///< Establish comment delimiters for the language
|
||||
uint4 getInstructionComment(void) const { return instr_comment_type; } ///< Get the type of comments suitable within the body of a function
|
||||
void setInstructionComment(uint4 val) { instr_comment_type = val; } ///< Set the type of comments suitable within the body of a function
|
||||
void setNamespaceStrategy(namespace_strategy strat) { namespc_strategy = strat; } ///< Set how namespace tokens are displayed
|
||||
uint4 getHeaderComment(void) const { return head_comment_type; } ///< Get the type of comments suitable for a function header
|
||||
void setHeaderComment(uint4 val) { head_comment_type = val; } ///< Set the type of comments suitable for a function header
|
||||
bool emitsXml(void) const { return emit->emitsXml(); } ///< Does the low-level emitter, emit XML markup
|
||||
|
|
|
@ -6553,7 +6553,6 @@ bool RulePtrsubCharConstant::pushConstFurther(Funcdata &data,TypePointer *outtyp
|
|||
Varnode *vn = op->getIn(1);
|
||||
if (!vn->isConstant()) return false; // that is adding a constant
|
||||
uintb addval = vn->getOffset();
|
||||
if (addval > 128) return false; // Sanity check on string size
|
||||
addval *= op->getIn(2)->getOffset();
|
||||
val += addval;
|
||||
Varnode *newconst = data.newConstant(vn->getSize(),val);
|
||||
|
|
|
@ -31,7 +31,6 @@ import ghidra.program.model.lang.*;
|
|||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.pcode.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.CancelledListener;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import ghidra.xml.XmlPullParser;
|
||||
|
@ -131,7 +130,7 @@ public class DecompInterface {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns true if debug has been enabled for the current/next decompilation.
|
||||
* @return true if debug has been enabled for the current/next decompilation.
|
||||
*/
|
||||
public boolean debugEnabled() {
|
||||
return debug != null;
|
||||
|
@ -199,8 +198,8 @@ public class DecompInterface {
|
|||
/**
|
||||
* This is the main routine for making sure that a decompiler
|
||||
* process is active and that it is initialized properly
|
||||
* @throws IOException
|
||||
* @throws DecompileException
|
||||
* @throws IOException for any problems with the pipe to the decompiler process
|
||||
* @throws DecompileException for errors initializing decompiler options etc.
|
||||
*/
|
||||
protected void initializeProcess() throws IOException, DecompileException {
|
||||
if (decompCallback == null) {
|
||||
|
@ -233,7 +232,6 @@ public class DecompInterface {
|
|||
}
|
||||
if (xmlOptions != null) {
|
||||
decompProcess.setMaxResultSize(xmlOptions.getMaxPayloadMBytes());
|
||||
decompProcess.setShowNamespace(xmlOptions.isDisplayNamespaces());
|
||||
if (!decompProcess.sendCommand1Param("setOptions",
|
||||
xmlOptions.getXML(this)).toString().equals("t")) {
|
||||
throw new IOException("Did not accept decompiler options");
|
||||
|
@ -590,7 +588,6 @@ public class DecompInterface {
|
|||
try {
|
||||
verifyProcess();
|
||||
decompProcess.setMaxResultSize(xmlOptions.getMaxPayloadMBytes());
|
||||
decompProcess.setShowNamespace(xmlOptions.isDisplayNamespaces());
|
||||
return decompProcess.sendCommand1Param("setOptions",
|
||||
xmloptions.getXML(this)).toString().equals("t");
|
||||
}
|
||||
|
@ -701,8 +698,7 @@ public class DecompInterface {
|
|||
|
||||
if (program == null) {
|
||||
return new DecompileResults(func, pcodelanguage, null, dtmanage, decompileMessage, null,
|
||||
DecompileProcess.DisposeState.DISPOSED_ON_CANCEL,
|
||||
false /* cancelled--doesn't matter */);
|
||||
DecompileProcess.DisposeState.DISPOSED_ON_CANCEL);
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -747,7 +743,7 @@ public class DecompInterface {
|
|||
stream = res.getInputStream();
|
||||
}
|
||||
return new DecompileResults(func, pcodelanguage, compilerSpec, dtmanage, decompileMessage,
|
||||
stream, processState, isDisplayNamespace());
|
||||
stream, processState);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -796,12 +792,4 @@ public class DecompInterface {
|
|||
public CompilerSpec getCompilerSpec() {
|
||||
return compilerSpec;
|
||||
}
|
||||
|
||||
private boolean isDisplayNamespace() {
|
||||
if (xmlOptions == null) {
|
||||
return false; // not sure if this can happen
|
||||
}
|
||||
return xmlOptions.isDisplayNamespaces();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ import ghidra.util.xml.XmlUtilities;
|
|||
*/
|
||||
public class DecompileCallback {
|
||||
|
||||
public final static int MAX_SYMBOL_COUNT = 16;
|
||||
/**
|
||||
* Data returned for a query about strings
|
||||
*/
|
||||
|
@ -77,7 +78,6 @@ public class DecompileCallback {
|
|||
private PcodeDataTypeManager dtmanage;
|
||||
private Charset utf8Charset;
|
||||
private String nativeMessage;
|
||||
private boolean showNamespace;
|
||||
|
||||
private InstructionBlock lastPseudoInstructionBlock;
|
||||
private Disassembler pseudoDisassembler;
|
||||
|
@ -153,10 +153,6 @@ public class DecompileCallback {
|
|||
nativeMessage = msg;
|
||||
}
|
||||
|
||||
public void setShowNamespace(boolean showNamespace) {
|
||||
this.showNamespace = showNamespace;
|
||||
}
|
||||
|
||||
public synchronized int readXMLSize(String addrxml) {
|
||||
int attrstart = addrxml.indexOf("size=\"");
|
||||
if (attrstart >= 4) {
|
||||
|
@ -528,6 +524,15 @@ public class DecompileCallback {
|
|||
return sym.getName();
|
||||
}
|
||||
|
||||
private Namespace getNameSpaceByID(long id) {
|
||||
Symbol namespaceSym = program.getSymbolTable().getSymbol(id);
|
||||
Object namespace = namespaceSym.getObject();
|
||||
if (namespace instanceof Namespace) {
|
||||
return (Namespace) namespace;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getNamespacePrefix(Namespace ns) {
|
||||
if (ns.getID() == Namespace.GLOBAL_NAMESPACE_ID) {
|
||||
return null;
|
||||
|
@ -543,6 +548,72 @@ public class DecompileCallback {
|
|||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decide if a given name is used by any namespace between a starting namespace
|
||||
* and a stopping namespace. I.e. check for a name collision along a specific namespace path.
|
||||
* Currently, Ghidra is inefficient at calculating this perfectly, so this routine calculates
|
||||
* an approximation that can occasionally indicate a collision when there isn't.
|
||||
* @param name is the given name to check for collisions
|
||||
* @param startId is the id specifying the starting namespace
|
||||
* @param stopId is the id specifying the stopping namespace
|
||||
* @return true if the name (likely) occurs in one of the namespaces on the path
|
||||
*/
|
||||
public boolean isNameUsed(String name, long startId, long stopId) {
|
||||
Namespace namespace = getNameSpaceByID(startId);
|
||||
int pathSize = 0;
|
||||
Namespace curspace = namespace;
|
||||
long curId = namespace.getID();
|
||||
while (curId != stopId && curId != 0 && !(curspace instanceof Library)) {
|
||||
pathSize += 1;
|
||||
curspace = curspace.getParentNamespace();
|
||||
curId = curspace.getID();
|
||||
}
|
||||
long path[] = new long[pathSize];
|
||||
curspace = namespace;
|
||||
path[0] = startId;
|
||||
for (int i = 1; i < pathSize; ++i) {
|
||||
curspace = curspace.getParentNamespace();
|
||||
path[i] = curspace.getID();
|
||||
}
|
||||
int count = 0;
|
||||
SymbolIterator iter = program.getSymbolTable().getSymbols(name);
|
||||
for (;;) {
|
||||
if (!iter.hasNext()) {
|
||||
break;
|
||||
}
|
||||
count += 1;
|
||||
if (count > MAX_SYMBOL_COUNT) {
|
||||
break;
|
||||
}
|
||||
Namespace symSpace = iter.next().getParentNamespace();
|
||||
long id = symSpace.getID();
|
||||
if (id == Namespace.GLOBAL_NAMESPACE_ID) {
|
||||
continue; // Common case we know can't match anything in path
|
||||
}
|
||||
for (int i = 0; i < pathSize; ++i) {
|
||||
if (path[i] == id) {
|
||||
if (debug != null) {
|
||||
debug.nameIsUsed(symSpace, name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (count > MAX_SYMBOL_COUNT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an XML description of the formal namespace path to the given namespace
|
||||
* @param id is the ID of the given namespace
|
||||
* @return a parent XML tag
|
||||
*/
|
||||
public String getNamespacePath(long id) {
|
||||
Namespace namespace = getNameSpaceByID(id);
|
||||
StringBuilder buf = new StringBuilder();
|
||||
HighFunction.createNamespaceTag(buf, namespace, true);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private void generateHeaderCommentXML(Function func, StringBuilder buf) {
|
||||
Address addr = func.getEntryPoint();
|
||||
String text = listing.getComment(CodeUnit.PLATE_COMMENT, addr);
|
||||
|
@ -697,14 +768,13 @@ public class DecompileCallback {
|
|||
return null;
|
||||
}
|
||||
|
||||
HighFunction hfunc =
|
||||
new HighFunction(func, pcodelanguage, pcodecompilerspec, dtmanage, showNamespace);
|
||||
HighFunction hfunc = new HighFunction(func, pcodelanguage, pcodecompilerspec, dtmanage);
|
||||
|
||||
int extrapop = getExtraPopOverride(func, addr);
|
||||
hfunc.grabFromFunction(extrapop, false, (extrapop != default_extrapop));
|
||||
|
||||
HighSymbol funcSymbol = new HighFunctionSymbol(addr, 2, hfunc);
|
||||
Namespace namespc = func.getParentNamespace();
|
||||
Namespace namespc = funcSymbol.getNamespace();
|
||||
if (debug != null) {
|
||||
debug.getFNTypes(hfunc);
|
||||
}
|
||||
|
@ -802,16 +872,17 @@ public class DecompileCallback {
|
|||
}
|
||||
|
||||
private String buildResult(HighSymbol highSymbol, Namespace namespc) {
|
||||
StringBuilder res = new StringBuilder();
|
||||
res.append("<result>\n");
|
||||
res.append("<parent>\n");
|
||||
if (namespc == null) {
|
||||
res.append("<val/>"); // Assume global scope
|
||||
long namespaceId;
|
||||
if (namespc == null || namespc instanceof Library) {
|
||||
namespaceId = Namespace.GLOBAL_NAMESPACE_ID;
|
||||
}
|
||||
else {
|
||||
HighFunction.createNamespaceTag(res, namespc);
|
||||
namespaceId = namespc.getID();
|
||||
}
|
||||
res.append("</parent>\n");
|
||||
StringBuilder res = new StringBuilder();
|
||||
res.append("<result");
|
||||
SpecXmlUtils.encodeUnsignedIntegerAttribute(res, "id", namespaceId);
|
||||
res.append(">\n");
|
||||
if (debug != null) {
|
||||
StringBuilder res2 = new StringBuilder();
|
||||
HighSymbol.buildMapSymXML(res2, highSymbol);
|
||||
|
@ -938,14 +1009,14 @@ public class DecompileCallback {
|
|||
long diff = addr.getOffset() - entry.getOffset();
|
||||
if ((diff >= 0) && (diff < 8)) {
|
||||
HighFunction hfunc = new HighFunction(func, pcodelanguage, pcodecompilerspec,
|
||||
dtmanage, showNamespace);
|
||||
dtmanage);
|
||||
|
||||
int extrapop = getExtraPopOverride(func, addr);
|
||||
hfunc.grabFromFunction(extrapop, includeDefaultNames,
|
||||
(extrapop != default_extrapop));
|
||||
|
||||
HighSymbol functionSymbol = new HighFunctionSymbol(entry, (int) (diff + 1), hfunc);
|
||||
Namespace namespc = func.getParentNamespace();
|
||||
Namespace namespc = functionSymbol.getNamespace();
|
||||
if (debug != null) {
|
||||
debug.getFNTypes(hfunc);
|
||||
}
|
||||
|
|
|
@ -522,18 +522,19 @@ public class DecompileDebug {
|
|||
}
|
||||
while (scopename != null) {
|
||||
StringBuilder datahead = new StringBuilder();
|
||||
Namespace parentNamespace;
|
||||
datahead.append("<scope");
|
||||
// Force globalnamespace to have blank name
|
||||
if (scopename != globalnamespace) {
|
||||
if (scopename != globalnamespace && !(scopename instanceof Library)) {
|
||||
SpecXmlUtils.xmlEscapeAttribute(datahead, "name", scopename.getName());
|
||||
parentNamespace = scopename.getParentNamespace();
|
||||
}
|
||||
else {
|
||||
SpecXmlUtils.encodeStringAttribute(datahead, "name", "");
|
||||
parentNamespace = null;
|
||||
}
|
||||
datahead.append(">\n");
|
||||
datahead.append("<parent>\n");
|
||||
HighFunction.createNamespaceTag(datahead, scopename.getParentNamespace());
|
||||
datahead.append("</parent>\n");
|
||||
HighFunction.createNamespaceTag(datahead, parentNamespace, false);
|
||||
if (scopename != globalnamespace) {
|
||||
datahead.append("<rangeequalssymbols/>\n");
|
||||
}
|
||||
|
@ -676,6 +677,14 @@ public class DecompileDebug {
|
|||
cpool.add(buf.toString());
|
||||
}
|
||||
|
||||
public void nameIsUsed(Namespace spc, String nm) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append("<collision");
|
||||
SpecXmlUtils.xmlEscapeAttribute(buffer, "name", nm);
|
||||
buffer.append("/>\n");
|
||||
getMapped(spc, buffer.toString());
|
||||
}
|
||||
|
||||
public void addFlowOverride(Address addr,FlowOverride fo) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append("<flow type=\"");
|
||||
|
|
|
@ -230,6 +230,35 @@ public class DecompileOptions {
|
|||
private final static boolean COMMENTHEAD_OPTIONDEFAULT = true;
|
||||
private boolean commentHeadInclude;
|
||||
|
||||
public enum NamespaceStrategy {
|
||||
Minimal("minimal", "Minimally"),
|
||||
All("all", "Always"),
|
||||
Never("none", "Never");
|
||||
|
||||
private String label;
|
||||
private String optionString;
|
||||
|
||||
private NamespaceStrategy(String optString, String label) {
|
||||
this.label = label;
|
||||
this.optionString = optString;
|
||||
}
|
||||
|
||||
public String getOptionString() {
|
||||
return optionString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return label;
|
||||
}
|
||||
}
|
||||
|
||||
private final static String NAMESPACE_OPTIONSTRING = "Display.Display Namespaces";
|
||||
private final static String NAMESPACE_OPTIONDESCRIPTION =
|
||||
"Choose how/if namespace tokens should be displayed along with symbol names";
|
||||
private final static NamespaceStrategy NAMESPACE_OPTIONDEFAULT = NamespaceStrategy.Minimal;
|
||||
private NamespaceStrategy namespaceStrategy;
|
||||
|
||||
private final static String INTEGERFORMAT_OPTIONSTRING = "Display.Integer format";
|
||||
private final static String INTEGERFORMAT_OPTIONDESCRIPTION =
|
||||
"Choose how to display integers: as hexadecimal, decimal, or best fit";
|
||||
|
@ -317,13 +346,10 @@ public class DecompileOptions {
|
|||
"Number of Decompiled Functions to Cache in the Decompile Window";
|
||||
|
||||
private final static String LINE_NUMBER_MSG = "Display.Display Line Numbers";
|
||||
private final static String NAMESPACE_MSG = "Display.Display Namespaces";
|
||||
private final static String DECOMPILE_TIMEOUT = "Decompiler Timeout (seconds)";
|
||||
private final static String PAYLOAD_LIMIT = "Decompiler Max-Payload (MBytes)";
|
||||
private final static Boolean LINE_NUMBER_DEF = Boolean.TRUE;
|
||||
private final static Boolean NAMESPACES_DEF = Boolean.FALSE;
|
||||
private boolean displayLineNumbers;
|
||||
private boolean displayNamespaces;
|
||||
private int decompileTimeoutSeconds;
|
||||
private int payloadLimitMBytes;
|
||||
private int cachedResultsSize;
|
||||
|
@ -354,6 +380,7 @@ public class DecompileOptions {
|
|||
commentEOLInclude = COMMENTEOL_OPTIONDEFAULT;
|
||||
commentWARNInclude = COMMENTWARN_OPTIONDEFAULT;
|
||||
commentHeadInclude = COMMENTHEAD_OPTIONDEFAULT;
|
||||
namespaceStrategy = NAMESPACE_OPTIONDEFAULT;
|
||||
integerFormat = INTEGERFORMAT_OPTIONDEFAULT;
|
||||
keywordColor = HIGHLIGHT_KEYWORD_DEF;
|
||||
functionColor = HIGHLIGHT_FUNCTION_DEF;
|
||||
|
@ -367,7 +394,6 @@ public class DecompileOptions {
|
|||
codeViewerBackgroundColor = CODE_VIEWER_BACKGROUND_COLOR;
|
||||
defaultFont = DEFAULT_FONT;
|
||||
displayLineNumbers = LINE_NUMBER_DEF;
|
||||
displayNamespaces = NAMESPACES_DEF;
|
||||
displayLanguage = BasicCompilerSpec.DECOMPILER_OUTPUT_DEF;
|
||||
protoEvalModel = "default";
|
||||
decompileTimeoutSeconds = SUGGESTED_DECOMPILE_TIMEOUT_SECS;
|
||||
|
@ -414,6 +440,7 @@ public class DecompileOptions {
|
|||
commentPLATEInclude = opt.getBoolean(COMMENTPLATE_OPTIONSTRING, COMMENTPLATE_OPTIONDEFAULT);
|
||||
commentWARNInclude = opt.getBoolean(COMMENTWARN_OPTIONSTRING, COMMENTWARN_OPTIONDEFAULT);
|
||||
commentHeadInclude = opt.getBoolean(COMMENTHEAD_OPTIONSTRING, COMMENTHEAD_OPTIONDEFAULT);
|
||||
namespaceStrategy = opt.getEnum(NAMESPACE_OPTIONSTRING, NAMESPACE_OPTIONDEFAULT);
|
||||
integerFormat = opt.getEnum(INTEGERFORMAT_OPTIONSTRING, INTEGERFORMAT_OPTIONDEFAULT);
|
||||
keywordColor = opt.getColor(HIGHLIGHT_KEYWORD_MSG, HIGHLIGHT_KEYWORD_DEF);
|
||||
typeColor = opt.getColor(HIGHLIGHT_TYPE_MSG, HIGHLIGHT_TYPE_DEF);
|
||||
|
@ -432,7 +459,6 @@ public class DecompileOptions {
|
|||
defaultFont = SystemUtilities.adjustForFontSizeOverride(defaultFont);
|
||||
defaultSearchHighlightColor = opt.getColor(SEARCH_HIGHLIGHT_MSG, SEARCH_HIGHLIGHT_DEF);
|
||||
displayLineNumbers = opt.getBoolean(LINE_NUMBER_MSG, LINE_NUMBER_DEF);
|
||||
displayNamespaces = opt.getBoolean(NAMESPACE_MSG, NAMESPACES_DEF);
|
||||
decompileTimeoutSeconds = opt.getInt(DECOMPILE_TIMEOUT, SUGGESTED_DECOMPILE_TIMEOUT_SECS);
|
||||
payloadLimitMBytes = opt.getInt(PAYLOAD_LIMIT, SUGGESTED_MAX_PAYLOAD_BYTES);
|
||||
cachedResultsSize = opt.getInt(CACHED_RESULTS_SIZE_MSG, SUGGESTED_CACHED_RESULTS_SIZE);
|
||||
|
@ -541,6 +567,8 @@ public class DecompileOptions {
|
|||
COMMENTWARN_OPTIONDESCRIPTION);
|
||||
opt.registerOption(COMMENTHEAD_OPTIONSTRING, COMMENTHEAD_OPTIONDEFAULT, help,
|
||||
COMMENTHEAD_OPTIONDESCRIPTION);
|
||||
opt.registerOption(NAMESPACE_OPTIONSTRING, NAMESPACE_OPTIONDEFAULT, help,
|
||||
NAMESPACE_OPTIONDESCRIPTION);
|
||||
opt.registerOption(INTEGERFORMAT_OPTIONSTRING, INTEGERFORMAT_OPTIONDEFAULT, help,
|
||||
INTEGERFORMAT_OPTIONDESCRIPTION);
|
||||
opt.registerOption(HIGHLIGHT_KEYWORD_MSG, HIGHLIGHT_KEYWORD_DEF, help,
|
||||
|
@ -569,8 +597,6 @@ public class DecompileOptions {
|
|||
"The color used to highlight matches using the Find Dialog.");
|
||||
opt.registerOption(LINE_NUMBER_MSG, LINE_NUMBER_DEF, help,
|
||||
"Toggle for displaying line numbers in the decompiler.");
|
||||
opt.registerOption(NAMESPACE_MSG, NAMESPACES_DEF, help,
|
||||
"Toggle for dislaying namespaces for functions.");
|
||||
opt.registerOption(DECOMPILE_TIMEOUT, SUGGESTED_DECOMPILE_TIMEOUT_SECS, help,
|
||||
"The number of seconds to allow the decompiler to run before terminating the " +
|
||||
"decompiler.\nCurrently this does not affect the UI, which will run indefinitely. " +
|
||||
|
@ -654,6 +680,8 @@ public class DecompileOptions {
|
|||
appendOption(buf, "commentheader", "header", commentHeadInclude ? "on" : "off", "");
|
||||
appendOption(buf, "commentheader", "warningheader", commentWARNInclude ? "on" : "off", "");
|
||||
|
||||
appendOption(buf, "namespacestrategy", namespaceStrategy.getOptionString(), "", "");
|
||||
|
||||
appendOption(buf, "integerformat", integerFormat.getOptionString(), "", "");
|
||||
|
||||
appendOption(buf, "protoeval", protoEvalModel, "", "");
|
||||
|
@ -793,10 +821,6 @@ public class DecompileOptions {
|
|||
return displayLineNumbers;
|
||||
}
|
||||
|
||||
public boolean isDisplayNamespaces() {
|
||||
return displayNamespaces;
|
||||
}
|
||||
|
||||
public DecompilerLanguage getDisplayLanguage() {
|
||||
return displayLanguage;
|
||||
}
|
||||
|
|
|
@ -70,7 +70,6 @@ public class DecompileProcess {
|
|||
private int archId = -1; // architecture id for decomp process
|
||||
private DecompileCallback callback; // Callback interface for decompiler
|
||||
private int maxResultSizeMBYtes = 50; // maximum result size in MBytes to allow from decompiler
|
||||
private boolean showNamespace; // whether to show namespaces for functions
|
||||
|
||||
public enum DisposeState {
|
||||
NOT_DISPOSED, // Process was/is not disposed
|
||||
|
@ -240,7 +239,7 @@ public class DecompileProcess {
|
|||
/**
|
||||
* Transfer bytes written to -out- to decompiler process
|
||||
* @param out has the collected byte for this write
|
||||
* @throws IOException
|
||||
* @throws IOException for any problems with the output stream
|
||||
*/
|
||||
private void writeBytes(PackedBytes out) throws IOException {
|
||||
write(string_start);
|
||||
|
@ -288,6 +287,9 @@ public class DecompileProcess {
|
|||
throw new Exception("Bad decompiler query: " + name);
|
||||
}
|
||||
switch (name.charAt(3)) {
|
||||
case 'a': // isNameUsed
|
||||
isNameUsed();
|
||||
break;
|
||||
case 'B':
|
||||
getBytes(); // getBytes
|
||||
break;
|
||||
|
@ -314,6 +316,9 @@ public class DecompileProcess {
|
|||
case 'M':
|
||||
getMappedSymbolsXML(); // getMappedSymbolsXML
|
||||
break;
|
||||
case 'N':
|
||||
getNamespacePath();
|
||||
break;
|
||||
case 'P':
|
||||
getPcodePacked(); // getPacked
|
||||
break;
|
||||
|
@ -427,14 +432,14 @@ public class DecompileProcess {
|
|||
* @param pspecxml = string containing .pspec xml
|
||||
* @param cspecxml = string containing .cspec xml
|
||||
* @param tspecxml = XML string containing translator spec
|
||||
* @throws IOException
|
||||
* @throws DecompileException
|
||||
* @param coretypesxml = XML description of core data-types
|
||||
* @throws IOException for problems with the pipe to the decompiler process
|
||||
* @throws DecompileException for problems executing the command
|
||||
*/
|
||||
public synchronized void registerProgram(DecompileCallback cback, String pspecxml,
|
||||
String cspecxml, String tspecxml, String coretypesxml)
|
||||
throws IOException, DecompileException {
|
||||
callback = cback;
|
||||
callback.setShowNamespace(showNamespace);
|
||||
|
||||
setup();
|
||||
String restring = null;
|
||||
|
@ -457,9 +462,9 @@ public class DecompileProcess {
|
|||
|
||||
/**
|
||||
* Free decompiler resources
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws DecompileException
|
||||
* @return 1 if a program was actively deregistered, 0 otherwise
|
||||
* @throws IOException for problems with the pipe to the decompiler
|
||||
* @throws DecompileException for problems executing the command
|
||||
*/
|
||||
public synchronized int deregisterProgram() throws IOException, DecompileException {
|
||||
if (!statusGood) {
|
||||
|
@ -483,8 +488,8 @@ public class DecompileProcess {
|
|||
* Send a single command to the decompiler with no parameters and return response
|
||||
* @param command is the name of the command to execute
|
||||
* @return the response String
|
||||
* @throws IOException
|
||||
* @throws DecompileException
|
||||
* @throws IOException for any problems with the pipe to the decompiler process
|
||||
* @throws DecompileException for any problems executing the command
|
||||
*/
|
||||
public synchronized LimitedByteBuffer sendCommand(String command)
|
||||
throws IOException, DecompileException {
|
||||
|
@ -515,8 +520,8 @@ public class DecompileProcess {
|
|||
* @param param an additional parameter for the command
|
||||
* @param timeoutSecs the number of seconds to run before timing out
|
||||
* @return the response string
|
||||
* @throws IOException
|
||||
* @throws DecompileException
|
||||
* @throws IOException for any problems with the pipe to the decompiler process
|
||||
* @throws DecompileException for any problems while executing the command
|
||||
*/
|
||||
public synchronized LimitedByteBuffer sendCommand1ParamTimeout(String command, String param,
|
||||
int timeoutSecs) throws IOException, DecompileException {
|
||||
|
@ -555,8 +560,8 @@ public class DecompileProcess {
|
|||
* @param param1 is the first parameter string
|
||||
* @param param2 is the second parameter string
|
||||
* @return the result string
|
||||
* @throws IOException
|
||||
* @throws DecompileException
|
||||
* @throws IOException for any problems with the pipe to the decompiler process
|
||||
* @throws DecompileException for problems executing the command
|
||||
*/
|
||||
public synchronized LimitedByteBuffer sendCommand2Params(String command, String param1,
|
||||
String param2) throws IOException, DecompileException {
|
||||
|
@ -584,18 +589,13 @@ public class DecompileProcess {
|
|||
this.maxResultSizeMBYtes = maxResultSizeMBytes;
|
||||
}
|
||||
|
||||
public void setShowNamespace(boolean showNamespace) {
|
||||
this.showNamespace = showNamespace;
|
||||
callback.setShowNamespace(showNamespace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a command to the decompiler with one parameter and return the result
|
||||
* @param command is the command string
|
||||
* @param param1 is the parameter as a string
|
||||
* @return the result string
|
||||
* @throws IOException
|
||||
* @throws DecompileException
|
||||
* @throws IOException for problems with the pipe to the decompiler process
|
||||
* @throws DecompileException for problems executing the command
|
||||
*/
|
||||
public synchronized LimitedByteBuffer sendCommand1Param(String command, String param1)
|
||||
throws IOException, DecompileException {
|
||||
|
@ -711,6 +711,31 @@ public class DecompileProcess {
|
|||
write(query_response_end);
|
||||
}
|
||||
|
||||
private void getNamespacePath() throws IOException {
|
||||
String idString = readQueryString();
|
||||
long id = Long.parseLong(idString, 16);
|
||||
String res = callback.getNamespacePath(id);
|
||||
write(query_response_start);
|
||||
if ((res != null) && (res.length() != 0)) {
|
||||
writeString(res);
|
||||
}
|
||||
write(query_response_end);
|
||||
}
|
||||
|
||||
private void isNameUsed() throws IOException {
|
||||
String name = readQueryString();
|
||||
String startString = readQueryString();
|
||||
String stopString = readQueryString();
|
||||
long startId = Long.parseLong(startString, 16);
|
||||
long stopId = Long.parseLong(stopString, 16);
|
||||
boolean res = callback.isNameUsed(name, startId, stopId);
|
||||
write(query_response_start);
|
||||
write(string_start);
|
||||
write(res ? 't' : 'f');
|
||||
write(string_end);
|
||||
write(query_response_end);
|
||||
}
|
||||
|
||||
private void getExternalRefXML() throws IOException {
|
||||
String refaddr = readQueryString();
|
||||
String res = callback.getExternalRefXML(refaddr);
|
||||
|
|
|
@ -62,12 +62,10 @@ public class DecompileResults {
|
|||
private ClangTokenGroup docroot; // C code parsed from XML
|
||||
private String errMsg; // Error message from decompiler
|
||||
private DecompileProcess.DisposeState processState;
|
||||
private boolean showNamespace; // include namespace when displaying function names
|
||||
|
||||
public DecompileResults(Function f, Language language, CompilerSpec compilerSpec,
|
||||
PcodeDataTypeManager d, String e, InputStream raw,
|
||||
DecompileProcess.DisposeState processState,
|
||||
boolean showNamespace) {
|
||||
DecompileProcess.DisposeState processState) {
|
||||
function = f;
|
||||
this.language = language;
|
||||
this.compilerSpec = compilerSpec;
|
||||
|
@ -76,7 +74,6 @@ public class DecompileResults {
|
|||
hfunc = null;
|
||||
hparamid = null;
|
||||
docroot = null;
|
||||
this.showNamespace = showNamespace;
|
||||
//dumpResults(raw);
|
||||
parseRawString(raw);
|
||||
}
|
||||
|
@ -226,7 +223,7 @@ public class DecompileResults {
|
|||
XmlElement el = parser.peek();
|
||||
if (el.getName().equals("function")) {
|
||||
if (hfunc == null) {
|
||||
hfunc = new HighFunction(function, language, compilerSpec, dtmanage, showNamespace);
|
||||
hfunc = new HighFunction(function, language, compilerSpec, dtmanage);
|
||||
hfunc.readXML(parser);
|
||||
}
|
||||
else { // TODO: This is an ugly kludge to get around duplicate XML tag names
|
||||
|
@ -237,9 +234,7 @@ public class DecompileResults {
|
|||
}
|
||||
}
|
||||
else if (el.getName().equals("parammeasures")) {
|
||||
hparamid =
|
||||
new HighParamID(function, language, compilerSpec, dtmanage,
|
||||
showNamespace);
|
||||
hparamid = new HighParamID(function, language, compilerSpec, dtmanage);
|
||||
hparamid.readXML(parser);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -89,18 +89,22 @@ final public class DexAnalysisState implements AnalysisState {
|
|||
* @return the EncodedMethod
|
||||
*/
|
||||
public EncodedMethod getEncodedMethod(Address addr) {
|
||||
if (methodMap == null) {
|
||||
buildMethodMap();
|
||||
synchronized (this) {
|
||||
if (methodMap == null) {
|
||||
buildMethodMap();
|
||||
|
||||
}
|
||||
}
|
||||
return methodMap.get(addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return persistent <code>DexAnalysisState</code> which corresponds to the specified program instance.
|
||||
* @param program
|
||||
* @param program is the specified program instance
|
||||
* @return <code>DexAnalysisState</code> 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) {
|
||||
|
|
|
@ -51,22 +51,19 @@ public class HighFunction extends PcodeSyntaxTree {
|
|||
private GlobalSymbolMap globalSymbols;
|
||||
private List<JumpTable> jumpTables;
|
||||
private List<DataTypeSymbol> protoOverrides;
|
||||
private boolean showNamespace = true;
|
||||
|
||||
/**
|
||||
* @param function function associated with the higher level function abstraction.
|
||||
* @param language description of the processor language of the function
|
||||
* @param compilerSpec description of the compiler that produced the function
|
||||
* @param dtManager data type manager
|
||||
* @param showNamespace true signals to print function names with their namespace
|
||||
*/
|
||||
public HighFunction(Function function, Language language, CompilerSpec compilerSpec,
|
||||
PcodeDataTypeManager dtManager, boolean showNamespace) {
|
||||
PcodeDataTypeManager dtManager) {
|
||||
super(function.getProgram().getAddressFactory(), dtManager);
|
||||
func = function;
|
||||
this.language = language;
|
||||
this.compilerSpec = compilerSpec;
|
||||
this.showNamespace = showNamespace;
|
||||
localSymbols = new LocalSymbolMap(this, "stack");
|
||||
globalSymbols = new GlobalSymbolMap(this);
|
||||
proto = new FunctionPrototype(localSymbols, function);
|
||||
|
@ -260,9 +257,9 @@ public class HighFunction extends PcodeSyntaxTree {
|
|||
public void readXML(XmlPullParser parser) throws PcodeXMLException {
|
||||
XmlElement start = parser.start("function");
|
||||
String name = start.getAttribute("name");
|
||||
if (!func.getName(showNamespace).equals(name)) {
|
||||
if (!func.getName().equals(name)) {
|
||||
throw new PcodeXMLException(
|
||||
"Function name mismatch: " + func.getName(showNamespace) + " + " + name);
|
||||
"Function name mismatch: " + func.getName() + " + " + name);
|
||||
}
|
||||
while (!parser.peek().isEnd()) {
|
||||
XmlElement subel = parser.peek();
|
||||
|
@ -436,11 +433,12 @@ public class HighFunction extends PcodeSyntaxTree {
|
|||
* addresses near its entry point.
|
||||
*
|
||||
* @param id is the id associated with the function symbol
|
||||
* @param namespace is the namespace containing the function symbol
|
||||
* @param entryPoint pass null to use the function entryPoint, pass an address to force an entry point
|
||||
* @param size describes how many bytes the function occupies as code
|
||||
* @return the XML string
|
||||
*/
|
||||
public String buildFunctionXML(long id, Address entryPoint, int size) {
|
||||
public String buildFunctionXML(long id, Namespace namespace, Address entryPoint, int size) {
|
||||
// Functions aren't necessarily contiguous with the smallest address being the entry point
|
||||
// So size needs to be smaller than size of the contiguous chunk containing the entry point
|
||||
StringBuilder resBuf = new StringBuilder();
|
||||
|
@ -448,7 +446,7 @@ public class HighFunction extends PcodeSyntaxTree {
|
|||
if (id != 0) {
|
||||
SpecXmlUtils.encodeUnsignedIntegerAttribute(resBuf, "id", id);
|
||||
}
|
||||
SpecXmlUtils.xmlEscapeAttribute(resBuf, "name", func.getName(showNamespace));
|
||||
SpecXmlUtils.xmlEscapeAttribute(resBuf, "name", func.getName());
|
||||
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "size", size);
|
||||
if (func.isInline()) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(resBuf, "inline", true);
|
||||
|
@ -463,12 +461,12 @@ public class HighFunction extends PcodeSyntaxTree {
|
|||
else {
|
||||
resBuf.append(Varnode.buildXMLAddress(entryPoint)); // Address is forced on XML
|
||||
}
|
||||
resBuf.append(localSymbols.buildLocalDbXML());
|
||||
localSymbols.buildLocalDbXML(resBuf, namespace);
|
||||
proto.buildPrototypeXML(resBuf, getDataTypeManager());
|
||||
if ((jumpTables != null) && (jumpTables.size() > 0)) {
|
||||
resBuf.append("<jumptablelist>\n");
|
||||
for (int i = 0; i < jumpTables.size(); ++i) {
|
||||
jumpTables.get(i).buildXml(resBuf);
|
||||
for (JumpTable jumpTable : jumpTables) {
|
||||
jumpTable.buildXml(resBuf);
|
||||
}
|
||||
resBuf.append("</jumptablelist>\n");
|
||||
}
|
||||
|
@ -478,8 +476,7 @@ public class HighFunction extends PcodeSyntaxTree {
|
|||
}
|
||||
if ((protoOverrides != null) && (protoOverrides.size() > 0)) {
|
||||
PcodeDataTypeManager dtmanage = getDataTypeManager();
|
||||
for (int i = 0; i < protoOverrides.size(); ++i) {
|
||||
DataTypeSymbol sym = protoOverrides.get(i);
|
||||
for (DataTypeSymbol sym : protoOverrides) {
|
||||
Address addr = sym.getAddress();
|
||||
FunctionPrototype fproto = new FunctionPrototype(
|
||||
(FunctionSignature) sym.getDataType(), compilerSpec, false);
|
||||
|
@ -618,22 +615,39 @@ public class HighFunction extends PcodeSyntaxTree {
|
|||
}
|
||||
}
|
||||
|
||||
static public void createNamespaceTag(StringBuilder buf, Namespace namespc) {
|
||||
if (namespc == null) {
|
||||
return;
|
||||
}
|
||||
ArrayList<String> arr = new ArrayList<String>();
|
||||
Namespace curspc = namespc;
|
||||
while (curspc != null) {
|
||||
arr.add(0, curspc.getName());
|
||||
curspc = curspc.getParentNamespace();
|
||||
}
|
||||
buf.append("<val/>\n"); // Force global scope to have empty name
|
||||
for (int i = 1; i < arr.size(); ++i) {
|
||||
buf.append("<val>");
|
||||
SpecXmlUtils.xmlEscape(buf, arr.get(i));
|
||||
buf.append("</val>\n");
|
||||
/**
|
||||
* Append an XML <parent> tag to the buffer describing the formal path elements
|
||||
* from the root (global) namespace up to the given namespace
|
||||
* @param buf is the buffer to write to
|
||||
* @param namespace is the namespace being described
|
||||
* @param includeId is true if the XML tag should include namespace ids
|
||||
*/
|
||||
static public void createNamespaceTag(StringBuilder buf, Namespace namespace,
|
||||
boolean includeId) {
|
||||
buf.append("<parent>\n");
|
||||
if (namespace != null) {
|
||||
ArrayList<Namespace> arr = new ArrayList<Namespace>();
|
||||
Namespace curspc = namespace;
|
||||
while (curspc != null) {
|
||||
arr.add(0, curspc);
|
||||
if (curspc instanceof Library) {
|
||||
break; // Treat library namespace as root
|
||||
}
|
||||
curspc = curspc.getParentNamespace();
|
||||
}
|
||||
buf.append("<val/>\n"); // Force global scope to have empty name
|
||||
for (int i = 1; i < arr.size(); ++i) {
|
||||
Namespace curScope = arr.get(i);
|
||||
buf.append("<val");
|
||||
if (includeId) {
|
||||
SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "id", curScope.getID());
|
||||
}
|
||||
buf.append('>');
|
||||
SpecXmlUtils.xmlEscape(buf, curScope.getName());
|
||||
buf.append("</val>\n");
|
||||
}
|
||||
}
|
||||
buf.append("</parent>\n");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,7 +17,9 @@ package ghidra.program.model.pcode;
|
|||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.VariableStorage;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
/**
|
||||
|
@ -54,11 +56,25 @@ public class HighFunctionSymbol extends HighSymbol {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Namespace getNamespace() {
|
||||
Function func = function.getFunction();
|
||||
Namespace namespc = func.getParentNamespace();
|
||||
while (func.isThunk() && namespc.getID() == Namespace.GLOBAL_NAMESPACE_ID) {
|
||||
// Thunks can be in a different namespace than the thunked function.
|
||||
// We choose the thunk's namespace unless it is the global namespace
|
||||
func = func.getThunkedFunction(false);
|
||||
namespc = func.getParentNamespace();
|
||||
}
|
||||
return namespc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveXML(StringBuilder buf) {
|
||||
MappedEntry entry = (MappedEntry) getFirstWholeMap();
|
||||
String funcString =
|
||||
function.buildFunctionXML(getId(), entry.getStorage().getMinAddress(), entry.getSize());
|
||||
function.buildFunctionXML(getId(), getNamespace(), entry.getStorage().getMinAddress(),
|
||||
entry.getSize());
|
||||
buf.append(funcString);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,23 +48,20 @@ public class HighParamID extends PcodeSyntaxTree {
|
|||
private Integer protoextrapop;
|
||||
private List<ParamMeasure> inputlist = new ArrayList<ParamMeasure>();
|
||||
private List<ParamMeasure> outputlist = new ArrayList<ParamMeasure>();
|
||||
private boolean showNamespace = true;
|
||||
|
||||
/**
|
||||
* @param function function associated with the higher level function abstraction.
|
||||
* @param language language parser used to disassemble/get info on the language.
|
||||
* @param compilerSpec the compiler spec.
|
||||
* @param dtManager data type manager.
|
||||
* @param showNamespace true to show the parameters namespace.
|
||||
*/
|
||||
public HighParamID(Function function, Language language, CompilerSpec compilerSpec,
|
||||
PcodeDataTypeManager dtManager, boolean showNamespace) {
|
||||
PcodeDataTypeManager dtManager) {
|
||||
super(function.getProgram().getAddressFactory(), dtManager);
|
||||
func = function;
|
||||
|
||||
modelname = null;
|
||||
protoextrapop = PrototypeModel.UNKNOWN_EXTRAPOP;
|
||||
this.showNamespace = showNamespace;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -137,8 +134,8 @@ public class HighParamID extends PcodeSyntaxTree {
|
|||
public void readXML(XmlPullParser parser) throws PcodeXMLException {
|
||||
XmlElement start = parser.start("parammeasures");
|
||||
functionname = start.getAttribute("name");
|
||||
if (!func.getName(showNamespace).equals(functionname)) {
|
||||
throw new PcodeXMLException("Function name mismatch: " + func.getName(showNamespace) +
|
||||
if (!func.getName().equals(functionname)) {
|
||||
throw new PcodeXMLException("Function name mismatch: " + func.getName() +
|
||||
" + " + functionname);
|
||||
}
|
||||
while (!parser.peek().isEnd()) {
|
||||
|
@ -157,10 +154,12 @@ public class HighParamID extends PcodeSyntaxTree {
|
|||
subel = parser.start("proto");
|
||||
modelname = subel.getAttribute("model");
|
||||
String val = subel.getAttribute("extrapop");
|
||||
if (val.equals("unknown"))
|
||||
if (val.equals("unknown")) {
|
||||
protoextrapop = PrototypeModel.UNKNOWN_EXTRAPOP;
|
||||
else
|
||||
}
|
||||
else {
|
||||
protoextrapop = SpecXmlUtils.decodeInt(val);
|
||||
}
|
||||
parser.end(subel);
|
||||
}
|
||||
else if (subel.getName().equals("input")) {
|
||||
|
@ -243,23 +242,28 @@ public class HighParamID extends PcodeSyntaxTree {
|
|||
try {
|
||||
//TODO: Currently, only storing one output, so looking for the best to report. When possible, change this to report all
|
||||
int best_index = 0;
|
||||
if (getNumOutputs() > 1)
|
||||
for (int i = 1; i < getNumOutputs(); i++)
|
||||
if (getNumOutputs() > 1) {
|
||||
for (int i = 1; i < getNumOutputs(); i++) {
|
||||
if (getOutput(i).getRank() < getOutput(best_index).getRank()) {//TODO: create mirror of ranks on high side (instead of using numbers?)
|
||||
best_index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (getNumOutputs() != 0) {
|
||||
ParamMeasure pm = getOutput(best_index);
|
||||
pm.getRank(); //TODO (maybe): this value is not used or stored on the java side at this point
|
||||
Varnode vn = pm.getVarnode();
|
||||
DataType dataType;
|
||||
if (storeDataTypes)
|
||||
if (storeDataTypes) {
|
||||
dataType = pm.getDataType();
|
||||
else
|
||||
}
|
||||
else {
|
||||
dataType = dtManage.findUndefined(vn.getSize());
|
||||
}
|
||||
//Msg.debug(this, "func: " + func.getName() + " -- type: " + dataType.getName());
|
||||
if (!(dataType == null || dataType instanceof VoidDataType))
|
||||
if (!(dataType == null || dataType instanceof VoidDataType)) {
|
||||
func.setReturn(dataType, buildStorage(vn), SourceType.ANALYSIS);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
|
@ -282,10 +286,12 @@ public class HighParamID extends PcodeSyntaxTree {
|
|||
DataType dataType;
|
||||
//Msg.debug(this, "function(" + func.getName() + ")--param size: " + vn.getSize() +
|
||||
// "--type before store: " + pm.getDataType().getName());
|
||||
if (storeDataTypes)
|
||||
if (storeDataTypes) {
|
||||
dataType = pm.getDataType();
|
||||
else
|
||||
}
|
||||
else {
|
||||
dataType = dtManage.findUndefined(vn.getSize());
|
||||
}
|
||||
Variable v =
|
||||
new ParameterImpl(null, dataType, buildStorage(vn),
|
||||
func.getProgram());
|
||||
|
|
|
@ -19,6 +19,7 @@ import ghidra.program.model.address.Address;
|
|||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.listing.VariableStorage;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.util.xml.SpecXmlUtils;
|
||||
import ghidra.xml.XmlElement;
|
||||
|
@ -130,6 +131,18 @@ public class HighSymbol {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the namespace owning this symbol, if it exists.
|
||||
* @return the Namespace object or null
|
||||
*/
|
||||
public Namespace getNamespace() {
|
||||
Symbol sym = getSymbol();
|
||||
if (sym != null) {
|
||||
return sym.getParentNamespace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate a particular HighVariable with this symbol. This is used to link the symbol
|
||||
* into the decompiler's description of how a function manipulates a particular symbol.
|
||||
|
|
|
@ -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);
|
||||
|
@ -325,31 +326,29 @@ public class LocalSymbolMap {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return an XML document string representing this local variable map.
|
||||
* Output an XML document representing this local variable map.
|
||||
* @param resBuf is the buffer to write to
|
||||
* @param namespace if the namespace of the function
|
||||
*/
|
||||
public String buildLocalDbXML() { // Get memory mapped local variables
|
||||
StringBuilder res = new StringBuilder();
|
||||
res.append("<localdb");
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "lock", false);
|
||||
SpecXmlUtils.encodeStringAttribute(res, "main", spacename);
|
||||
res.append(">\n");
|
||||
res.append("<scope");
|
||||
SpecXmlUtils.xmlEscapeAttribute(res, "name", func.getFunction().getName());
|
||||
res.append(">\n");
|
||||
res.append("<parent>\n");
|
||||
HighFunction.createNamespaceTag(res, func.getFunction().getParentNamespace());
|
||||
res.append("</parent>\n");
|
||||
res.append("<rangelist/>\n"); // Empty address range
|
||||
res.append("<symbollist>\n");
|
||||
public void buildLocalDbXML(StringBuilder resBuf, Namespace namespace) { // Get memory mapped local variables
|
||||
resBuf.append("<localdb");
|
||||
SpecXmlUtils.encodeBooleanAttribute(resBuf, "lock", false);
|
||||
SpecXmlUtils.encodeStringAttribute(resBuf, "main", spacename);
|
||||
resBuf.append(">\n");
|
||||
resBuf.append("<scope");
|
||||
SpecXmlUtils.xmlEscapeAttribute(resBuf, "name", func.getFunction().getName());
|
||||
resBuf.append(">\n");
|
||||
HighFunction.createNamespaceTag(resBuf, namespace, false);
|
||||
resBuf.append("<rangelist/>\n"); // Empty address range
|
||||
resBuf.append("<symbollist>\n");
|
||||
Iterator<HighSymbol> iter = symbolMap.values().iterator();
|
||||
while (iter.hasNext()) {
|
||||
HighSymbol sym = iter.next();
|
||||
HighSymbol.buildMapSymXML(res, sym);
|
||||
HighSymbol.buildMapSymXML(resBuf, sym);
|
||||
}
|
||||
res.append("</symbollist>\n");
|
||||
res.append("</scope>\n");
|
||||
res.append("</localdb>\n");
|
||||
return res.toString();
|
||||
resBuf.append("</symbollist>\n");
|
||||
resBuf.append("</scope>\n");
|
||||
resBuf.append("</localdb>\n");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue