Convert to Scope ids

This commit is contained in:
caheckman 2020-09-30 11:29:50 -04:00
parent 97b04cac7e
commit 7c0b21f0dc
17 changed files with 394 additions and 327 deletions

View File

@ -102,7 +102,7 @@ Architecture::Architecture(void)
commentdb = (CommentDatabase *)0;
stringManager = (StringManager *)0;
cpool = (ConstantPool *)0;
symboltab = new Database(this);
symboltab = (Database *)0;
context = (ContextDatabase *)0;
print = PrintLanguageCapability::getDefault()->buildLanguage(this);
printlist.push_back(print);
@ -131,7 +131,8 @@ Architecture::~Architecture(void)
for(int4 i=0;i<extra_pool_rules.size();++i)
delete extra_pool_rules[i];
delete symboltab;
if (symboltab != (Database *)0)
delete symboltab;
for(int4 i=0;i<(int4)printlist.size();++i)
delete printlist[i];
delete options;
@ -371,7 +372,7 @@ void Architecture::setPrintLanguage(const string &nm)
void Architecture::globalify(void)
{
Scope *scope = buildGlobalScope();
Scope *scope = symboltab->getGlobalScope();
int4 nm = numSpaces();
for(int4 i=0;i<nm;++i) {
@ -528,16 +529,16 @@ void Architecture::buildContext(DocumentStorage &store)
context = new ContextInternal();
}
/// If it does not already exist create the glocal Scope object
/// Create the database object, which currently doesn't not depend on any configuration
/// data. Then create the root (global) scope and attach it to the database.
/// \param store is the storage for any configuration data
/// \return the global Scope object
Scope *Architecture::buildGlobalScope(void)
Scope *Architecture::buildDatabase(DocumentStorage &store)
{
Scope *globscope = symboltab->getGlobalScope();
if (globscope == (Scope *)0) { // Make sure global scope exists
globscope = new ScopeInternal("",this);
symboltab->attachScope(globscope,(Scope *)0);
}
symboltab = new Database(this,true);
Scope *globscope = new ScopeInternal(0,"",this);
symboltab->attachScope(globscope,(Scope *)0);
return globscope;
}
@ -802,7 +803,7 @@ void Architecture::parseDefaultProto(const Element *el)
void Architecture::parseGlobal(const Element *el)
{
Scope *scope = buildGlobalScope();
Scope *scope = symboltab->getGlobalScope();
const List &list(el->getChildren());
List::const_iterator iter;
@ -829,15 +830,15 @@ void Architecture::parseGlobal(const Element *el)
void Architecture::addOtherSpace(void)
{
Scope *scope = buildGlobalScope();
Scope *scope = symboltab->getGlobalScope();
AddrSpace *otherSpace = getSpaceByName("OTHER");
symboltab->addRange(scope,otherSpace,0,otherSpace->getHighest());
if (otherSpace->isOverlayBase()) {
int4 num = numSpaces();
for(int4 i=0;i<num;++i){
OverlaySpace *ospc = (OverlaySpace *)getSpace(i);
if (ospc->getBaseSpace() != otherSpace) continue;
if (ospc->getBaseSpace() != otherSpace) continue;
int4 num = numSpaces();
for(int4 i=0;i<num;++i){
AddrSpace *ospc = getSpace(i);
if (!ospc->isOverlay()) continue;
if (((OverlaySpace *)ospc)->getBaseSpace() != otherSpace) continue;
symboltab->addRange(scope,ospc,0,otherSpace->getHighest());
}
}
@ -1279,9 +1280,11 @@ void Architecture::init(DocumentStorage &store)
buildCommentDB(store);
buildStringManager(store);
buildConstantPool(store);
buildDatabase(store);
restoreFromSpec(store);
print->getCastStrategy()->setTypeFactory(types);
symboltab->adjustCaches(); // In case the specs created additional address spaces
postSpecFile(); // Let subclasses do things after translate is ready
buildInstructions(store); // Must be called after translate is built

View File

@ -206,7 +206,7 @@ protected:
void addNoHighPtr(const Range &rng); ///< Add a new region where pointers do not exist
// Factory routines for building this architecture
virtual Scope *buildGlobalScope(void); ///< Build the global scope for this executable
virtual Scope *buildDatabase(DocumentStorage &store); ///< Build the database and global scope for this executable
/// \brief Build the Translator object
///

View File

@ -15,6 +15,7 @@
*/
#include "database.hh"
#include "funcdata.hh"
#include "crc32.hh"
#include <ctype.h>
uint8 Symbol::ID_BASE = 0x4000000000000000L;
@ -812,38 +813,14 @@ MapIterator MapIterator::operator++(int4 i) {
return tmp;
}
/// Sort first on name, then on dedupId
/// \param op2 is the key to compare with \b this
/// \return \b true if \b this should be ordered before the other key
bool ScopeKey::operator<(const ScopeKey &op2) const
{
int4 comp = name.compare(op2.name);
if (comp < 0) return true;
if (comp > 0) return false;
return (dedupId < op2.dedupId); // Use dedupId to (possibly) allow scopes with same name
}
/// Attach the child as an immediate sub-scope of \b this.
/// Take responsibility of the child's memory: the child will be freed when this is freed.
/// May throw RecovError if there is a duplicate name issue
/// \param child is the Scope to make a child
void Scope::attachScope(Scope *child)
{
child->parent = this;
pair<const ScopeKey,Scope *> value(ScopeKey(child->name,child->uniqueId),child);
pair<ScopeMap::iterator,bool> res;
if (child->name.size()==0)
throw LowlevelError("Non-global scope has empty name");
res = children.insert(value);
if (res.second==false) {
ostringstream s;
s << "Duplicate scope name: ";
s << child->getFullName();
delete child;
throw RecovError(s.str());
}
children[child->uniqueId] = child; // uniqueId is guaranteed to be unique by Database
}
/// The indicated child Scope is deleted
@ -856,6 +833,29 @@ void Scope::detachScope(ScopeMap::iterator iter)
delete child;
}
/// \brief Create a Scope id based on the scope's name and its parent's id
///
/// Create a globally unique id for a scope simply from its name.
/// \param baseId is the scope id of the parent scope
/// \param nm is the name of scope
/// \return the hash of the parent id and name
uint8 Scope::hashScopeName(uint8 baseId,const string &nm)
{
uint4 reg1 = (uint4)(baseId>>32);
uint4 reg2 = (uint4)baseId;
reg1 = crc_update(reg1, 0xa9);
reg2 = crc_update(reg2, reg1);
for(int4 i=0;i<nm.size();++i) {
uint4 val = nm[i];
reg1 = crc_update(reg1, val);
reg2 = crc_update(reg2, reg1);
}
uint8 res = reg1;
res = (res << 32) | reg2;
return res;
}
/// \brief Query for Symbols starting at a given address, which match a given \b usepoint
///
/// Searching starts at a first scope, continuing thru parents up to a second scope,
@ -1270,20 +1270,40 @@ LabSymbol *Scope::queryCodeLabel(const Address &addr) const
return res;
}
/// Look for the (last) immediate child of \b this with a given name
/// Look for the immediate child of \b this with a given name
/// \param name is the child's name
/// \param strategy is \b true if hash of the name determines id
/// \return the child Scope or NULL if there is no child with that name
Scope *Scope::resolveScope(const string &name) const
Scope *Scope::resolveScope(const string &name,bool strategy) const
{
ScopeKey key(name,0xffffffff);
ScopeMap::const_iterator iter = children.upper_bound(key);
if (iter == children.begin()) return (Scope *)0; // All children are after -name-
--iter;
Scope *scope = (*iter).second;
if (scope->name == name)
return scope;
return (Scope *)0;
if (strategy) {
uint8 key = hashScopeName(uniqueId, name);
ScopeMap::const_iterator iter = children.find(key);
if (iter == children.end()) return (Scope *)0;
Scope *scope = (*iter).second;
if (scope->name == name)
return scope;
}
else if (name.length() > 0 && name[0] <= '9' && name[0] >= '0') {
// Allow the string to directly specify the id
istringstream s(name);
s.unsetf(ios::dec | ios::hex | ios::oct);
uint8 key;
s >> key;
ScopeMap::const_iterator iter = children.find(key);
if (iter == children.end()) return (Scope *)0;
return (*iter).second;
}
else {
ScopeMap::const_iterator iter;
for(iter=children.begin();iter!=children.end();++iter) {
Scope *scope = (*iter).second;
if (scope->name == name)
return scope;
}
}
return (Scope *)0;
}
/// Discover a sub-scope or containing Scope of \b this, that \e owns the given
@ -1395,27 +1415,6 @@ string Scope::getFullName(void) const
return fname;
}
/// Put the names of \b this and all its parent Scopes into an array in order.
/// The name of the first entry will generally be the name of the global Scope
/// \param vec is the array in which to store the names
void Scope::getNameSegments(vector<string> &vec) const
{
int4 count = 0;
const Scope *cur = this;
while(cur != (Scope *)0) { // Count number of segments
count += 1;
cur = cur->parent;
}
vec.resize(count);
cur = this;
while(cur != (Scope *)0) { // Copy each segment
count -= 1;
vec[count] = cur->name;
cur = cur->parent;
}
}
/// Put the parent scopes of \b this into an array in order, starting with the global scope.
/// \param vec is storage for the array of scopes
void Scope::getScopePath(vector<const Scope *> &vec) const
@ -1718,17 +1717,17 @@ bool Scope::isReadOnly(const Address &addr,int4 size,const Address &usepoint) co
return ((flags & Varnode::readonly)!=0);
}
Scope *ScopeInternal::buildSubScope(const string &nm)
Scope *ScopeInternal::buildSubScope(uint8 id,const string &nm)
{
return new ScopeInternal(nm,glb);
return new ScopeInternal(id,nm,glb);
}
void ScopeInternal::addSymbolInternal(Symbol *sym)
{
if (sym->symbolId == 0) {
sym->symbolId = Symbol::ID_BASE + (((uint8)uniqueId & 0xffff) << 40) + nextUniqueId;
sym->symbolId = Symbol::ID_BASE + ((uniqueId & 0xffff) << 40) + nextUniqueId;
nextUniqueId += 1;
}
try {
@ -1857,17 +1856,18 @@ list<SymbolEntry>::iterator ScopeInternal::endDynamic(void)
return dynamicentry.end();
}
/// \param id is the globally unique id associated with the scope
/// \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,this)
ScopeInternal::ScopeInternal(uint8 id,const string &nm,Architecture *g)
: Scope(id,nm,g,this)
{
nextUniqueId = 0;
maptable.resize(g->numSpaces(),(EntryMap *)0);
}
ScopeInternal::ScopeInternal(const string &nm,Architecture *g, Scope *own)
: Scope(nm,g,own)
ScopeInternal::ScopeInternal(uint8 id,const string &nm,Architecture *g, Scope *own)
: Scope(id,nm,g,own)
{
nextUniqueId = 0;
maptable.resize(g->numSpaces(),(EntryMap *)0);
@ -2015,6 +2015,12 @@ void ScopeInternal::clearUnlockedCategory(int4 cat)
}
}
void ScopeInternal::adjustCaches(void)
{
maptable.resize(glb->numSpaces(),(EntryMap *)0);
}
void ScopeInternal::removeSymbolMappings(Symbol *symbol)
{
@ -2509,45 +2515,18 @@ string ScopeInternal::makeNameUnique(const string &nm) const
return resString;
}
/// Given a list of name strings, write out each one in an XML \<val> tag.
/// \param s is the output stream
/// \param vec is the list of names
void ScopeInternal::savePathXml(ostream &s,const vector<string> &vec)
{
for(int4 i=0;i<vec.size();++i) {
s << "<val>";
xml_escape(s,vec[i].c_str());
s << "</val>\n";
}
}
/// Given an element, parse all of its children (as \<val> tags) and
/// put each of their content into a string array.
/// \param vec will hold the resulting string array
/// \param el is the XML element
void ScopeInternal::restorePathXml(vector<string> &vec,const Element *el)
{
const List &list(el->getChildren());
List::const_iterator iter;
for(iter=list.begin();iter!=list.end();++iter)
vec.push_back( (*iter)->getContent() );
}
void ScopeInternal::saveXml(ostream &s) const
{
s << "<scope";
a_v(s,"name",name);
a_v_u(s,"id",uniqueId);
s << ">\n";
vector<string> fname;
getNameSegments(fname);
fname.pop_back(); // Pop 1 level to get parent path
s << "<parent>\n";
savePathXml(s,fname);
s << "</parent>\n";
if (getParent() != (const Scope *)0) {
s << "<parent";
a_v_u(s, "id", getParent()->getId());
s << "/>\n";
}
getRangeTree().saveXml(s);
if (!nametree.empty()) {
@ -2669,8 +2648,11 @@ void ScopeInternal::restoreXml(const Element *el)
const Element *subel;
iter = list.begin();
++iter; // Skip <parent>, processed elsewhere
subel = *iter;
if (subel->getName() == "parent") {
++iter; // Skip <parent> tag processed elsewhere
subel = *iter;
}
if (subel->getName() == "rangelist") {
RangeList newrangetree;
newrangetree.restoreXml(subel,glb);
@ -2804,17 +2786,18 @@ void Database::clearResolve(Scope *scope)
}
}
/// This recursively performs clearResolve() on the Scope and any sub-scopes
/// This recursively clears references in idmap or in resolvemap.
/// \param scope is the given Scope to clear
void Database::clearResolveRecursive(Scope *scope)
void Database::clearReferences(Scope *scope)
{
ScopeMap::const_iterator iter = scope->children.begin();
ScopeMap::const_iterator enditer = scope->children.end();
while(iter != enditer) {
clearResolveRecursive((*iter).second);
clearReferences((*iter).second);
++iter;
}
idmap.erase(scope->uniqueId);
clearResolve(scope);
}
@ -2833,6 +2816,18 @@ void Database::fillResolve(Scope *scope)
}
}
/// Initialize a new symbol table, with no initial scopes or symbols.
/// \param g is the Architecture that owns the symbol table
/// \param isByName is \b true if scope ids are calculated as a hash of the scope name.
Database::Database(Architecture *g,bool idByName)
{
glb=g;
globalscope=(Scope *)0;
flagbase.defaultValue()=0;
idByNameHash=idByName;
}
Database::~Database(void)
{
@ -2854,27 +2849,47 @@ void Database::attachScope(Scope *newscope,Scope *parent)
throw LowlevelError("Multiple global scopes");
if (newscope->name.size() != 0)
throw LowlevelError("Global scope does not have empty name");
newscope->assignId(0);
globalscope = newscope;
idmap[globalscope->uniqueId] = globalscope;
return;
}
newscope->assignId(nextScopeId);
nextScopeId += 1;
if (newscope->name.size()==0)
throw LowlevelError("Non-global scope has empty name");
pair<uint8,Scope *> value(newscope->uniqueId,newscope);
pair<ScopeMap::iterator,bool> res;
res = idmap.insert(value);
if (res.second==false) {
ostringstream s;
s << "Duplicate scope id: ";
s << newscope->getFullName();
delete newscope;
throw RecovError(s.str());
}
parent->attachScope(newscope);
}
/// Give \b this database the chance to inform existing scopes of any change to the
/// configuration, which may have changed since the initial scopes were created.
void Database::adjustCaches(void)
{
ScopeMap::iterator iter;
for(iter=idmap.begin();iter!=idmap.end();++iter) {
(*iter).second->adjustCaches();
}
}
/// \param scope is the given Scope
void Database::deleteScope(Scope *scope)
{
clearResolveRecursive(scope);
clearReferences(scope);
if (globalscope == scope) {
globalscope = (Scope *)0;
delete scope;
}
else {
ScopeKey key(scope->name,scope->uniqueId);
ScopeMap::iterator iter = scope->parent->children.find(key);
ScopeMap::iterator iter = scope->parent->children.find(scope->uniqueId);
if (iter == scope->parent->children.end())
throw LowlevelError("Could not remove parent reference to: "+scope->name);
scope->parent->detachScope(iter);
@ -2892,7 +2907,7 @@ void Database::deleteSubScopes(Scope *scope)
while(iter != enditer) {
curiter = iter;
++iter;
clearResolveRecursive((*curiter).second);
clearReferences((*curiter).second);
scope->detachScope(curiter);
}
}
@ -2952,42 +2967,33 @@ 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
/// Look for a Scope by id. If it does not exist, create a new scope
/// with the given name and parent scope.
/// \param id is the global id of the Scope
/// \param nm is the given name of the Scope
/// \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 *Database::findCreateScope(uint8 id,const string &nm,Scope *parent)
{
Scope *res = parent->resolveScope(nm);
Scope *res = resolveScope(id);
if (res != (Scope *)0)
return res;
res = globalscope->buildSubScope(nm);
res = globalscope->buildSubScope(id,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
/// global Scope is assumed, and the name is assumed to refer to a child.
/// \param subnames is the \e path of names
/// \return the desired Scope or NULL if a matching name isn't found
Scope *Database::resolveScope(const vector<string> &subnames) const
/// Find a Scope object, given its global id. Return null if id is not mapped to a Scope.
/// \param id is the global id
/// \return the matching Scope or null
Scope *Database::resolveScope(uint8 id) const
{
if (subnames.size()==0) return (Scope *)0;
Scope *curScope = globalscope;
int4 i=0;
if (subnames[0].size()==0) // blank name matches global scope
i += 1;
for(;i<subnames.size();++i) {
if (curScope == (Scope *)0)
break;
curScope = curScope->resolveScope(subnames[i]);
}
return curScope;
ScopeMap::const_iterator iter = idmap.find(id);
if (iter != idmap.end())
return (*iter).second;
return (Scope *)0;
}
/// \brief Get the Scope (and base name) associated with a qualified Symbol name
@ -3014,7 +3020,7 @@ Scope *Database::resolveScopeFromSymbolName(const string &fullname,const string
endmark = fullname.find(delim,mark);
if (endmark == string::npos) break;
string scopename = fullname.substr(mark,endmark-mark);
start = start->resolveScope(scopename);
start = start->resolveScope(scopename,idByNameHash);
if (start == (Scope *)0) // Was the scope name bad
return start;
mark = endmark + delim.size();
@ -3038,6 +3044,8 @@ Scope *Database::resolveScopeFromSymbolName(const string &fullname,const string
Scope *Database::findCreateScopeFromSymbolName(const string &fullname,const string &delim,string &basename,
Scope *start)
{
if (!idByNameHash)
throw LowlevelError("Scope name hashes not allowed");
if (start == (Scope *)0)
start = globalscope;
@ -3047,7 +3055,8 @@ Scope *Database::findCreateScopeFromSymbolName(const string &fullname,const stri
endmark = fullname.find(delim,mark);
if (endmark == string::npos) break;
string scopename = fullname.substr(mark,endmark-mark);
start = findCreateSubscope(scopename, start);
uint8 nameId = Scope::hashScopeName(start->uniqueId, scopename);
start = findCreateScope(nameId, scopename, start);
mark = endmark + delim.size();
}
basename = fullname.substr(mark,endmark);
@ -3130,7 +3139,10 @@ void Database::saveXml(ostream &s) const
{
partmap<Address,uint4>::const_iterator piter,penditer;
s << "<db>\n";
s << "<db";
if (idByNameHash)
a_v_b(s, "scopeidbyname", true);
s << ">\n";
// Save the property change points
piter = flagbase.begin();
penditer = flagbase.end();
@ -3148,34 +3160,22 @@ void Database::saveXml(ostream &s) const
s << "</db>\n";
}
/// \brief Read an XML \<parent> tag for a Scope path
///
/// The \<parent> tag is assumed to either be the first child of
/// the given element, or the first child of the first child.
/// From the \<parent>, the \e name attribute is passed back and
/// a Scope path is parsed from sub-tags.
/// \param el is the given element (with \<parent> as a child)
/// \param name will hold the \e name attribute
/// \param parnames will hold the Scope path
void Database::parseParentTag(const Element *el,string &name,vector<string> &parnames)
/// Parse the given element for the scope id of the parent.
/// Look up the parent scope and return it.
/// Throw an error if there is no matching scope
/// \param el is the given element
/// \return the matching scope
Scope *Database::parseParentTag(const Element *el)
{
const List &list1(el->getChildren());
const Element *subel1 = *list1.begin();
if (subel1->getName() == "parent") {
name = el->getAttributeValue("name");
ScopeInternal::restorePathXml(parnames,subel1);
return;
}
const List &list2(subel1->getChildren());
const Element *subel2 = *list2.begin();
if (subel2->getName() != "parent")
throw LowlevelError("Could not find scopes <parent> tag");
name = subel1->getAttributeValue("name");
ScopeInternal::restorePathXml(parnames,subel2);
istringstream s(el->getAttributeValue("id"));
uint8 id = -1;
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> id;
Scope *res = resolveScope(id);
if (res == (Scope *)0)
throw LowlevelError("Could not find scope matching id");
return res;
}
/// The children of a \<db> tag are examined to recover Scope and Symbol objects.
@ -3183,6 +3183,11 @@ void Database::parseParentTag(const Element *el,string &name,vector<string> &par
void Database::restoreXml(const Element *el)
{
idByNameHash = false; // Default
for(int4 i=0;i<el->getNumAttributes();++i) {
if (el->getAttributeName(i) == "scopeidbyname")
idByNameHash = xml_readbool(el->getAttributeValue(i));
}
const List &list(el->getChildren());
List::const_iterator iter;
@ -3202,31 +3207,40 @@ void Database::restoreXml(const Element *el)
for(;iter!=list.end();++iter) {
const Element *subel = *iter;
string name;
vector<string> parnames;
parseParentTag(subel,name,parnames);
parnames.push_back(name);
Scope *new_scope = globalscope;
for(int4 i=1;i<parnames.size();++i)
new_scope = findCreateSubscope(parnames[i], new_scope);
new_scope->restoreXml(subel);
string name = subel->getAttributeValue("name");
istringstream s(subel->getAttributeValue("id"));
s.unsetf(ios::dec | ios::hex | ios::oct);
uint8 id;
s >> id;
const List &sublist(subel->getChildren());
Scope *parentScope = (Scope *)0;
if (!sublist.empty()) {
const Element *parTag = sublist.front();
if (parTag->getName() == "parent")
parentScope = parseParentTag(parTag);
}
Scope *newScope = findCreateScope(id, name, parentScope);
newScope->restoreXml(subel);
}
}
/// This allows incremental building of the Database from multiple XML sources.
/// An empty Scope must already be allocated. It is registered with \b this Database,
/// and then populated with Symbol objects based as the content of a given \<scope> tag.
/// and then populated with Symbol objects based as the content of a given XML tag.
/// The tag can either be a \<scope> itself, or another tag that wraps a \<scope> tag
/// as its first child.
/// \param el is the given \<scope> element
/// \param new_scope is the empty Scope
void Database::restoreXmlScope(const Element *el,Scope *new_scope)
/// \param newScope is the empty Scope
void Database::restoreXmlScope(const Element *el,Scope *newScope)
{
Scope *par_scope;
vector<string> parnames;
parseParentTag(el,new_scope->name,parnames); // Shove recovered basename straight into new_scope
par_scope = resolveScope(parnames);
if (par_scope == (Scope *)0)
throw LowlevelError("Bad parent scope");
attachScope(new_scope,par_scope);
new_scope->restoreXml(el);
const List &list(el->getChildren());
const Element *parTag = list.front();
if (el->getName() != "scope") {
const List &sublist(parTag->getChildren());
parTag = sublist.front();
}
Scope *parentScope = parseParentTag(parTag);
attachScope(newScope,parentScope);
newScope->restoreXml(el);
}

View File

@ -377,18 +377,7 @@ public:
}
};
/// \brief A key for looking up child symbol scopes within a parent, based on name
///
/// A key for mapping from name to Scope. The class includes a deduplication component
/// if Scopes with the same name are allowed.
class ScopeKey {
string name; ///< The name of the Scope
uintb dedupId; ///< A duplication id for the Scope
public:
ScopeKey(const string &nm,uint4 id) { name = nm; dedupId = id; } ///< Construct given a name and id
bool operator<(const ScopeKey &op2) const; ///< Comparison operator
};
typedef map<ScopeKey,Scope *> ScopeMap; ///< A map from ScopeKey to Scope
typedef map<uint8,Scope *> ScopeMap; ///< A map from id to Scope
/// \brief A collection of Symbol objects within a single (namespace or functional) scope
///
@ -420,12 +409,12 @@ class Scope {
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
static uint8 hashScopeName(uint8 baseId,const string &nm);
protected:
Architecture *glb; ///< Architecture of \b this scope
string name; ///< Name of \b this scope
Funcdata *fd; ///< (If non-null) the function which \b this is the local Scope for
uint4 uniqueId; ///< Unique id for the scope, for deduping scope names, assigning symbol ids
uint8 uniqueId; ///< Unique id for the scope, for deduping scope names, assigning symbol ids
static const Scope *stackAddr(const Scope *scope1,
const Scope *scope2,
const Address &addr,
@ -460,9 +449,10 @@ protected:
///
/// 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 id is the globally unique id associated with the scope
/// \param nm is the name of the new scope
/// \return the new Scope object
virtual Scope *buildSubScope(const string &nm)=0;
virtual Scope *buildSubScope(uint8 id,const string &nm)=0;
virtual void restrictScope(Funcdata *f); ///< Convert \b this to a local Scope
@ -512,8 +502,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,Scope *own) {
name = nm; glb = g; parent = (Scope *)0; fd = (Funcdata *)0; uniqueId = 0; owner=own;
Scope(uint8 id,const string &nm,Architecture *g,Scope *own) {
uniqueId = id; name = nm; glb = g; parent = (Scope *)0; fd = (Funcdata *)0; owner=own;
#ifdef OPACTION_DEBUG
debugon = false;
#endif
@ -530,6 +520,11 @@ public:
virtual void clearUnlocked(void)=0; ///< Clear all unlocked symbols from \b this scope
virtual void clearUnlockedCategory(int4 cat)=0; ///< Clear unlocked symbols of the given category from \b this scope
/// \brief Let scopes internally adjust any caches
///
/// This is called once after Architecture configuration is complete.
virtual void adjustCaches(void)=0;
/// \brief Query if the given range is owned by \b this Scope
///
/// All bytes in the range must be owned, and ownership can be informed by
@ -680,6 +675,7 @@ public:
const Address &addr,const Address &usepoint);
const string &getName(void) const { return name; } ///< Get the name of the Scope
uint8 getId(void) const { return uniqueId; } ///< Get the globally unique id
bool isGlobal(void) const { return (fd == (Funcdata *)0); } ///< Return \b true if \b this scope is global
// The main global querying routines
@ -695,7 +691,7 @@ public:
Funcdata *queryExternalRefFunction(const Address &addr) const; ///< Look-up a function thru an \e external \e reference
LabSymbol *queryCodeLabel(const Address &addr) const; ///< Look-up a code label by address
Scope *resolveScope(const string &name) const; ///< Find a child Scope of \b this
Scope *resolveScope(const string &name, bool strategy) const; ///< Find a child Scope of \b this
Scope *discoverScope(const Address &addr,int4 sz,const Address &usepoint); ///< Find the owning Scope of a given memory range
ScopeMap::const_iterator childrenBegin() const { return children.begin(); } ///< Beginning iterator of child scopes
ScopeMap::const_iterator childrenEnd() const { return children.end(); } ///< Ending iterator of child scopes
@ -705,7 +701,6 @@ public:
void setThisPointer(Symbol *sym,bool val) { sym->setThisPointer(val); } ///< Toggle the given Symbol as the "this" pointer
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<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
@ -735,7 +730,7 @@ class ScopeInternal : public Scope {
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 Scope *buildSubScope(uint8 id,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,
@ -747,13 +742,14 @@ protected:
SymbolNameTree multiEntrySet; ///< Set of symbols with multiple entries
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
ScopeInternal(uint8 id,const string &nm,Architecture *g); ///< Construct the Scope
ScopeInternal(uint8 id,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);
virtual void clearUnlocked(void);
virtual void clearUnlockedCategory(int4 cat);
virtual void adjustCaches(void);
virtual ~ScopeInternal(void);
virtual MapIterator begin(void) const;
virtual MapIterator end(void) const;
@ -797,8 +793,6 @@ public:
void assignDefaultNames(int4 &base); ///< Assign a default name (via buildVariableName) to any unnamed symbol
set<Symbol *>::const_iterator beginMultiEntry(void) const { return multiEntrySet.begin(); } ///< Start of symbols with more than one entry
set<Symbol *>::const_iterator endMultiEntry(void) const { return multiEntrySet.end(); } ///< End of symbols with more than one entry
static void savePathXml(ostream &s,const vector<string> &vec); ///< Save a path with \<val> tags
static void restorePathXml(vector<string> &vec,const Element *el); ///< Restore path from \<val> tags
};
/// \brief An Address range associated with the symbol Scope that owns it
@ -850,19 +844,21 @@ typedef rangemap<ScopeMapper> ScopeResolve; ///< A map from address to the owni
/// memory ranges. This allows important properties like \e read-only and \e volatile to
/// be put down even if the Symbols aren't yet known.
class Database {
Architecture *glb; ///< The Architecture to which this symbol table is attached
Scope *globalscope; ///< A quick reference to the \e global Scope
ScopeResolve resolvemap; ///< The Address to \e namespace map
Architecture *glb; ///< Architecture to which this symbol table is attached
Scope *globalscope; ///< Quick reference to the \e global Scope
ScopeResolve resolvemap; ///< Address to \e namespace map
ScopeMap idmap; ///< Map from id to Scope
partmap<Address,uint4> flagbase; ///< Map of global properties
uint4 nextScopeId; ///< Id for next attached scope (0 reserved for global scope)
bool idByNameHash; ///< True if scope ids are built from hash of name
void clearResolve(Scope *scope); ///< Clear the \e ownership ranges associated with the given Scope
void clearResolveRecursive(Scope *scope); ///< Clear the \e ownership ranges of a given Scope and its children
void clearReferences(Scope *scope); ///< Clear any map references to the given Scope and its children
void fillResolve(Scope *scope); ///< Add the \e ownership ranges of the given Scope to the map
static void parseParentTag(const Element *el,string &name,vector<string> &parnames);
Scope *parseParentTag(const Element *el); ///< Figure out parent scope given \<parent> tag.
public:
Database(Architecture *g) { glb=g; globalscope=(Scope *)0; flagbase.defaultValue()=0; nextScopeId=1; } ///< Constructor
Database(Architecture *g,bool idByName); ///< Constructor
~Database(void); ///< Destructor
Architecture *getArch(void) const { return glb; } ///< Get the Architecture associate with \b this
void adjustCaches(void); ///< Let scopes adjust after configuration is finished
void attachScope(Scope *newscope,Scope *parent); ///< Register a new Scope
void deleteScope(Scope *scope); ///< Delete the given Scope and all its sub-scopes
void deleteSubScopes(Scope *scope); ///< Delete all sub-scopes of the given Scope
@ -871,9 +867,9 @@ public:
void addRange(Scope *scope,AddrSpace *spc,uintb first,uintb last); ///< Add an address range to the \e ownership of a Scope
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 *resolveScope(uint8 id) const; ///< Look-up a Scope by id
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 *findCreateScope(uint8,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);
@ -883,7 +879,7 @@ public:
const partmap<Address,uint4> &getProperties(void) const { return flagbase; } ///< Get the entire property map
void saveXml(ostream &s) const; ///< Save the whole Database to an XML stream
void restoreXml(const Element *el); ///< Recover the whole database from XML
void restoreXmlScope(const Element *el,Scope *new_scope); ///< Register and fill out a single Scope from XML
void restoreXmlScope(const Element *el,Scope *newScope); ///< Register and fill out a single Scope from an XML \<scope> tag
};
/// \param sc is the scope containing the new symbol

View File

@ -16,18 +16,19 @@
#include "database_ghidra.hh"
#include "funcdata.hh"
Scope *ScopeGhidra::buildSubScope(const string &nm)
Scope *ScopeGhidra::buildSubScope(uint8 id,const string &nm)
{
return new ScopeGhidraNamespace(nm,ghidra);
return new ScopeGhidraNamespace(id,nm,ghidra);
}
/// \param g is the Architecture and connection to the Ghidra client
///
ScopeGhidra::ScopeGhidra(ArchitectureGhidra *g)
: Scope("",g,this)
: Scope(0,"",g,this)
{
ghidra = g;
cache = new ScopeInternal("",g,this);
cache = new ScopeInternal(0,"",g,this);
cacheDirty = false;
}
@ -46,15 +47,16 @@ Scope *ScopeGhidra::reresolveScope(uint8 id) const
{
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
Database *symboltab = ghidra->symboltab;
Scope *cacheScope = symboltab->resolveScope(id);
if (cacheScope != (Scope *)0)
return cacheScope; // 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)
Scope *curscope = symboltab->getGlobalScope(); // Get pointer to ourselves (which is not const)
try {
const List &list(doc->getRoot()->getChildren());
List::const_iterator iter = list.begin();
@ -66,16 +68,7 @@ Scope *ScopeGhidra::reresolveScope(uint8 id) const
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;
curscope = symboltab->findCreateScope(scopeId, el->getContent(), curscope);
}
delete doc;
}
@ -260,7 +253,6 @@ void ScopeGhidra::clear(void)
{
cache->clear();
holes.clear();
namespaceMap.clear();
if (cacheDirty) {
ghidra->symboltab->setProperties(flagbaseDefault); // Restore database properties to defaults
cacheDirty = false;
@ -415,6 +407,6 @@ bool ScopeGhidraNamespace::isNameUsed(const string &nm,const Scope *op2) const
if (ArchitectureGhidra::isDynamicSymbolName(nm))
return false; // Just assume default FUN_ and DAT_ names don't collide
const ScopeGhidraNamespace *otherScope = dynamic_cast<const ScopeGhidraNamespace *>(op2);
uint8 otherId = (otherScope != (const ScopeGhidraNamespace *)0) ? otherScope->getClientId() : 0;
return ghidra->isNameUsed(nm, scopeId, otherId);
uint8 otherId = (otherScope != (const ScopeGhidraNamespace *)0) ? otherScope->getId() : 0;
return ghidra->isNameUsed(nm, uniqueId, otherId);
}

View File

@ -36,7 +36,6 @@ 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
@ -48,7 +47,7 @@ class ScopeGhidra : public Scope {
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 Scope *buildSubScope(uint8 id,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"); }
@ -77,6 +76,7 @@ public:
virtual void clearAttribute(Symbol *sym,uint4 attr) { cache->clearAttribute(sym,attr); }
virtual void setDisplayFormat(Symbol *sym,uint4 attr) { cache->setDisplayFormat(sym,attr); }
virtual void adjustCaches(void) { cache->adjustCaches(); }
virtual SymbolEntry *findAddr(const Address &addr,const Address &usepoint) const;
virtual SymbolEntry *findContainer(const Address &addr,int4 size,
const Address &usepoint) const;
@ -127,16 +127,13 @@ public:
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,ArchitectureGhidra *g)
: ScopeInternal(nm,g) { ghidra = g; scopeId = 0; } ///< Constructor
ScopeGhidraNamespace(uint8 id,const string &nm,ArchitectureGhidra *g)
: ScopeInternal(id,nm,g) { ghidra = g; } ///< Constructor
uint8 getClientId(void) const { return scopeId; } ///< Get the Ghidra specific id
virtual bool isNameUsed(const string &nm,const Scope *op2) const;
};

View File

@ -45,7 +45,15 @@ Funcdata::Funcdata(const string &nm,Scope *scope,const Address &addr,FunctionSym
if (nm.size()==0)
localmap = (ScopeLocal *)0; // Filled in by restoreXml
else {
ScopeLocal *newMap = new ScopeLocal(stackid,this,glb);
uint8 id;
if (sym != (FunctionSymbol *)0)
id = sym->getId();
else {
// Missing a symbol, build unique id based on address
id = 0x57AB12CD;
id = (id << 32) | (addr.getOffset() & 0xffffffff);
}
ScopeLocal *newMap = new ScopeLocal(id,stackid,this,glb);
glb->symboltab->attachScope(newMap,scope); // This may throw and delete newMap
localmap = newMap;
funcp.setScope(localmap,baseaddr+ -1);
@ -735,7 +743,7 @@ uint8 Funcdata::restoreXml(const Element *el)
if ((*iter)->getName() == "localdb") {
if (localmap != (ScopeLocal *)0)
throw LowlevelError("Pre-existing local scope when restoring: "+name);
ScopeLocal *newMap = new ScopeLocal(stackid,this,glb);
ScopeLocal *newMap = new ScopeLocal(id,stackid,this,glb);
glb->symboltab->restoreXmlScope(*iter,newMap); // May delete newMap and throw
localmap = newMap;
}
@ -750,7 +758,7 @@ uint8 Funcdata::restoreXml(const Element *el)
else if ((*iter)->getName() == "prototype") {
if (localmap == (ScopeLocal *)0) {
// If we haven't seen a <localdb> tag yet, assume we have a default local scope
ScopeLocal *newMap = new ScopeLocal(stackid,this,glb);
ScopeLocal *newMap = new ScopeLocal(id,stackid,this,glb);
Scope *scope = glb->symboltab->getGlobalScope();
glb->symboltab->attachScope(newMap,scope); // May delete newMap and throw
localmap = newMap;
@ -763,7 +771,7 @@ uint8 Funcdata::restoreXml(const Element *el)
}
if (localmap == (ScopeLocal *)0) { // Seen neither <localdb> or <prototype>
// This is a function shell, so we provide default locals
ScopeLocal *newMap = new ScopeLocal(stackid,this,glb);
ScopeLocal *newMap = new ScopeLocal(id,stackid,this,glb);
Scope *scope = glb->symboltab->getGlobalScope();
glb->symboltab->attachScope(newMap,scope); // May delete newMap and throw
localmap = newMap;

View File

@ -923,7 +923,7 @@ void Funcdata::overrideFlow(const Address &addr,uint4 type)
else if (type == Override::CALL)
op = findPrimaryBranch(iter,enditer,true,false,true);
else if (type == Override::CALL_RETURN)
op = findPrimaryBranch(iter,enditer,true,false,true);
op = findPrimaryBranch(iter,enditer,true,true,true);
else if (type == Override::RETURN)
op = findPrimaryBranch(iter,enditer,true,true,false);

View File

@ -325,14 +325,12 @@ Translate *ArchitectureGhidra::buildTranslator(DocumentStorage &store)
return new GhidraTranslate(this);
}
Scope *ArchitectureGhidra::buildGlobalScope(void)
Scope *ArchitectureGhidra::buildDatabase(DocumentStorage &store)
{
Scope *globalscope = symboltab->getGlobalScope();
if (globalscope == (Scope *)0) { // Make sure global scope exists
globalscope = new ScopeGhidra(this);
symboltab->attachScope(globalscope,(Scope *)0);
}
symboltab = new Database(this,false);
Scope *globalscope = new ScopeGhidra(this);
symboltab->attachScope(globalscope,(Scope *)0);
return globalscope;
}

View File

@ -68,7 +68,7 @@ class ArchitectureGhidra : public Architecture {
bool sendsyntaxtree; ///< True if the syntax tree should be sent with function output
bool sendCcode; ///< True if C code should be sent with function output
bool sendParamMeasures; ///< True if measurements for argument and return parameters should be sent
virtual Scope *buildGlobalScope(void);
virtual Scope *buildDatabase(DocumentStorage &store);
virtual Translate *buildTranslator(DocumentStorage &store);
virtual void buildLoader(DocumentStorage &store);
virtual PcodeInjectLibrary *buildPcodeInjectLibrary(void);

View File

@ -343,16 +343,8 @@ static bool maxmatch(string &res,const string &op1,const string &op2)
{ // Set res to maximum characters in common
// at the beginning of op1 and op2
int4 len;
bool equal;
if (op1.size() == op2.size()) {
len = op1.size();
equal = true;
}
else {
equal = false;
len = ( op1.size() < op2.size() ) ? op1.size() : op2.size();
}
len = ( op1.size() < op2.size() ) ? op1.size() : op2.size();
res.erase();
for(int4 i=0;i<len;++i) {
@ -361,7 +353,7 @@ static bool maxmatch(string &res,const string &op1,const string &op2)
else
return false;
}
return equal;
return true;
}
int4 IfaceStatus::expandCom(vector<string> &expand,istream &s,

View File

@ -262,10 +262,11 @@ int4 RangeHint::compare(const RangeHint &op2) const
return 0;
}
/// \param id is the globally unique id associated with the function scope
/// \param spc is the (stack) address space associated with this function's local variables
/// \param fd is the function associated with these local variables
/// \param g is the Architecture
ScopeLocal::ScopeLocal(AddrSpace *spc,Funcdata *fd,Architecture *g) : ScopeInternal(fd->getName(),g)
ScopeLocal::ScopeLocal(uint8 id,AddrSpace *spc,Funcdata *fd,Architecture *g) : ScopeInternal(id,fd->getName(),g)
{
space = spc;

View File

@ -209,7 +209,7 @@ class ScopeLocal : public ScopeInternal {
void addRecommendName(Symbol *sym); ///< Convert the given symbol to a name recommendation
void collectNameRecs(void); ///< Collect names of unlocked Symbols on the stack
public:
ScopeLocal(AddrSpace *spc,Funcdata *fd,Architecture *g); ///< Constructor
ScopeLocal(uint8 id,AddrSpace *spc,Funcdata *fd,Architecture *g); ///< Constructor
virtual ~ScopeLocal(void) {} ///< Destructor
AddrSpace *getSpaceId(void) const { return space; } ///< Get the associated (stack) address space

View File

@ -500,7 +500,7 @@ public class DecompileCallback {
}
String res = getSymbolName(sym);
if (debug != null) {
debug.getSymbol(addr, res);
debug.getCodeSymbol(addr, sym.getID(), res, sym.getParentNamespace());
}
return res;
@ -563,7 +563,7 @@ public class DecompileCallback {
int pathSize = 0;
Namespace curspace = namespace;
long curId = namespace.getID();
while (curId != stopId && curId != 0 && !(curspace instanceof Library)) {
while (curId != stopId && curId != 0 && !HighFunction.collapseToGlobal(curspace)) {
pathSize += 1;
curspace = curspace.getParentNamespace();
curId = curspace.getID();
@ -610,7 +610,10 @@ public class DecompileCallback {
public String getNamespacePath(long id) {
Namespace namespace = getNameSpaceByID(id);
StringBuilder buf = new StringBuilder();
HighFunction.createNamespaceTag(buf, namespace, true);
HighFunction.createNamespaceTag(buf, namespace);
if (debug != null) {
debug.getNamespacePath(namespace);
}
return buf.toString();
}

View File

@ -17,6 +17,7 @@ package ghidra.app.decompiler;
import java.io.*;
import java.util.*;
import java.util.Map.Entry;
import ghidra.app.decompiler.DecompileCallback.StringData;
import ghidra.app.plugin.processors.sleigh.ContextCache;
@ -49,7 +50,6 @@ public class DecompileDebug {
private ArrayList<Namespace> dbscope; // Symbol query: scope
private ArrayList<String> database; // description of the symbol
private ArrayList<DataType> dtypes; // Data-types queried
private ArrayList<String> symbol; // Names of code labels
private ArrayList<String> context; // Tracked register values associated with an address
private ArrayList<String> cpool; // Constant pool results
private ArrayList<String> flowoverride; // Flow overrides associated with an address
@ -111,7 +111,6 @@ public class DecompileDebug {
dbscope = new ArrayList<Namespace>();
database = new ArrayList<String>();
dtypes = new ArrayList<DataType>();
symbol = new ArrayList<String>();
context = new ArrayList<String>();
cpool = new ArrayList<String>();
byteset = new TreeSet<ByteChunk>();
@ -192,9 +191,6 @@ public class DecompileDebug {
binimage += "\">\n";
debugStream.write(binimage.getBytes());
dumpBytes(debugStream);
for (String element : symbol) {
debugStream.write((element).getBytes());
}
debugStream.write("</binaryimage>\n".getBytes());
}
@ -511,50 +507,87 @@ public class DecompileDebug {
debugStream.write("</injectdebug>\n".getBytes());
}
private ArrayList<Namespace> orderNamespaces() {
TreeMap<Long, Namespace> namespaceMap = new TreeMap<Long, Namespace>();
for (Namespace namespace : dbscope) {
namespaceMap.put(namespace.getID(), namespace);
}
ArrayList<Namespace> res = new ArrayList<Namespace>();
while (!namespaceMap.isEmpty()) {
Entry<Long, Namespace> entry = namespaceMap.firstEntry();
Long curKey = entry.getKey();
Namespace curSpace = entry.getValue();
for (;;) {
Long key;
Namespace parent = curSpace.getParentNamespace();
if (parent == null) {
break;
}
if (HighFunction.collapseToGlobal(parent)) {
key = Long.valueOf(Namespace.GLOBAL_NAMESPACE_ID);
}
else {
key = Long.valueOf(parent.getID());
}
parent = namespaceMap.get(key);
if (parent == null) {
break;
}
curKey = key;
curSpace = parent;
}
res.add(curSpace);
namespaceMap.remove(curKey);
}
return res;
}
private void dumpDatabases(OutputStream debugStream) throws IOException {
Namespace scopename = null;
debugStream.write("<db>\n".getBytes());
for (int i = 0; i < database.size(); ++i) {
scopename = dbscope.get(i);
if (scopename != null) {
break;
}
}
while (scopename != null) {
ArrayList<Namespace> spaceList = orderNamespaces();
debugStream.write("<db scodeidbyname=\"false\">\n".getBytes());
for (Namespace element : spaceList) {
scopename = element;
StringBuilder datahead = new StringBuilder();
Namespace parentNamespace;
datahead.append("<scope");
// Force globalnamespace to have blank name
if (scopename != globalnamespace && !(scopename instanceof Library)) {
if (scopename != globalnamespace) {
SpecXmlUtils.xmlEscapeAttribute(datahead, "name", scopename.getName());
parentNamespace = scopename.getParentNamespace();
SpecXmlUtils.encodeUnsignedIntegerAttribute(datahead, "id", scopename.getID());
}
else {
SpecXmlUtils.encodeStringAttribute(datahead, "name", "");
SpecXmlUtils.encodeUnsignedIntegerAttribute(datahead, "id",
Namespace.GLOBAL_NAMESPACE_ID);
parentNamespace = null;
}
datahead.append(">\n");
HighFunction.createNamespaceTag(datahead, parentNamespace, false);
if (parentNamespace != null) {
long parentId =
HighFunction.collapseToGlobal(parentNamespace) ? Namespace.GLOBAL_NAMESPACE_ID
: parentNamespace.getID();
datahead.append("<parent");
SpecXmlUtils.encodeUnsignedIntegerAttribute(datahead, "id", parentId);
datahead.append("/>\n");
}
if (scopename != globalnamespace) {
datahead.append("<rangeequalssymbols/>\n");
}
datahead.append("<symbollist>\n");
debugStream.write(datahead.toString().getBytes());
for (int i = 0; i < database.size(); ++i) {
Namespace namespc = dbscope.get(i);
for (int j = 0; j < database.size(); ++j) {
Namespace namespc = dbscope.get(j);
if (namespc == scopename) {
debugStream.write((database.get(i)).getBytes());
dbscope.set(i, null);
String entry = database.get(j);
if (entry == null) {
continue; // String may be null
}
debugStream.write(entry.getBytes());
}
}
debugStream.write("</symbollist>\n</scope>\n".getBytes());
scopename = null;
for (Namespace element : dbscope) {
scopename = element;
if (scopename != null) {
break;
}
}
}
debugStream.write("</db>\n".getBytes());
}
@ -627,19 +660,34 @@ public class DecompileDebug {
comments = comm; // Already in XML form
}
public void getSymbol(Address addr, String name) {
public void getCodeSymbol(Address addr, long id, String name, Namespace namespace) {
StringBuilder buf = new StringBuilder();
buf.append("<symbol");
AddressSpace space = addr.getAddressSpace();
SpecXmlUtils.encodeStringAttribute(buf, "space", space.getPhysicalSpace().getName());
SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "offset", addr.getOffset());
buf.append("<mapsym>\n");
buf.append(" <labelsym");
SpecXmlUtils.xmlEscapeAttribute(buf, "name", name);
SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "id", id);
buf.append("/>\n");
symbol.add(buf.toString());
buf.append(" <addr");
Varnode.appendSpaceOffset(buf, addr);
buf.append("/>\n");
buf.append(" <rangelist/>\n");
buf.append("</mapsym>\n");
getMapped(namespace, buf.toString());
}
public void getNamespacePath(Namespace namespace) {
while (namespace != null) {
if (HighFunction.collapseToGlobal(namespace)) {
break; // Treat library namespace as root
}
dbscope.add(namespace); // Add namespace to guarantee <scope> tag
database.add(null); // Even if there isn't necessarily any symbols
namespace = namespace.getParentNamespace();
}
}
public void getMapped(Namespace namespc, String res) {
if (namespc == null) {
if (namespc == null || HighFunction.collapseToGlobal(namespc)) {
dbscope.add(globalnamespace);
}
else {

View File

@ -615,22 +615,33 @@ public class HighFunction extends PcodeSyntaxTree {
}
}
/**
* The decompiler treats some namespaces as equivalent to the "global" namespace.
* Return true if the given namespace is treated as equivalent.
* @param namespace is the namespace
* @return true if equivalent
*/
static final public boolean collapseToGlobal(Namespace namespace) {
if (namespace instanceof Library) {
return true;
}
return false;
}
/**
* Append an XML &lt;parent&gt; 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) {
static public void createNamespaceTag(StringBuilder buf, Namespace namespace) {
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) {
if (collapseToGlobal(curspc)) {
break; // Treat library namespace as root
}
curspc = curspc.getParentNamespace();
@ -639,9 +650,7 @@ public class HighFunction extends PcodeSyntaxTree {
for (int i = 1; i < arr.size(); ++i) {
Namespace curScope = arr.get(i);
buf.append("<val");
if (includeId) {
SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "id", curScope.getID());
}
SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "id", curScope.getID());
buf.append('>');
SpecXmlUtils.xmlEscape(buf, curScope.getName());
buf.append("</val>\n");

View File

@ -338,7 +338,13 @@ public class LocalSymbolMap {
resBuf.append("<scope");
SpecXmlUtils.xmlEscapeAttribute(resBuf, "name", func.getFunction().getName());
resBuf.append(">\n");
HighFunction.createNamespaceTag(resBuf, namespace, false);
resBuf.append("<parent");
long parentid = Namespace.GLOBAL_NAMESPACE_ID;
if (!HighFunction.collapseToGlobal(namespace)) {
parentid = namespace.getID();
}
SpecXmlUtils.encodeUnsignedIntegerAttribute(resBuf, "id", parentid);
resBuf.append("/>\n");
resBuf.append("<rangelist/>\n"); // Empty address range
resBuf.append("<symbollist>\n");
Iterator<HighSymbol> iter = symbolMap.values().iterator();