mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
More robust Symbol support for HighVariable
This commit is contained in:
parent
b99772a784
commit
cdbee3fe39
11 changed files with 268 additions and 174 deletions
|
@ -3890,66 +3890,16 @@ int4 ActionDynamicSymbols::apply(Funcdata &data)
|
|||
|
||||
{
|
||||
ScopeLocal *localmap = data.getScopeLocal();
|
||||
list<SymbolEntry>::const_iterator iter,enditer;
|
||||
list<SymbolEntry>::iterator iter,enditer;
|
||||
iter = localmap->beginDynamic();
|
||||
enditer = localmap->endDynamic();
|
||||
DynamicHash dhash;
|
||||
while(iter != enditer) {
|
||||
const SymbolEntry &entry( *iter );
|
||||
SymbolEntry *entry = &(*iter);
|
||||
++iter;
|
||||
Symbol *sym = entry.getSymbol();
|
||||
dhash.clear();
|
||||
Varnode *vn = dhash.findVarnode(&data,entry.getFirstUseAddress(),entry.getHash());
|
||||
if (vn == (Varnode *)0) {
|
||||
// localmap->removeSymbol(sym); // If it didn't map to anything, remove it
|
||||
continue;
|
||||
}
|
||||
if (vn->getSymbolEntry() == &entry) continue; // Already applied it
|
||||
if (vn->getSize() != entry.getSize()) {
|
||||
ostringstream s;
|
||||
s << "Unable to use symbol ";
|
||||
if (!sym->isNameUndefined())
|
||||
s << sym->getName() << ' ';
|
||||
s << ": Size does not match variable it labels";
|
||||
data.warningHeader(s.str());
|
||||
// localmap->removeSymbol(sym); // Don't use the symbol
|
||||
continue;
|
||||
}
|
||||
if (vn->getSymbolEntry() == &entry) continue; // Already applied it
|
||||
|
||||
if (vn->isImplied()) { // This should be finding an explicit, but a cast may have been inserted
|
||||
Varnode *newvn = (Varnode *)0;
|
||||
// Look at the "other side" of the cast
|
||||
if (vn->isWritten() && (vn->getDef()->code() == CPUI_CAST))
|
||||
newvn = vn->getDef()->getIn(0);
|
||||
else {
|
||||
PcodeOp *castop = vn->loneDescend();
|
||||
if ((castop != (PcodeOp *)0)&&(castop->code() == CPUI_CAST))
|
||||
newvn = castop->getOut();
|
||||
}
|
||||
// See if the varnode on the other side is explicit
|
||||
if ((newvn != (Varnode *)0)&&(newvn->isExplicit()))
|
||||
vn = newvn; // in which case we use it
|
||||
}
|
||||
|
||||
int4 offset;
|
||||
if (!entry.isPiece())
|
||||
offset = -1;
|
||||
else
|
||||
offset = entry.getOffset();
|
||||
vn->getHigh()->setSymbol(sym,offset);
|
||||
if (!sym->isTypeLocked()) { // If the dynamic symbol did not lock its type
|
||||
localmap->retypeSymbol(sym,vn->getType()); // use the type propagated into the varnode
|
||||
}
|
||||
else if (sym->getType() != vn->getType()) {
|
||||
ostringstream s;
|
||||
s << "Unable to use type for symbol " << sym->getName();
|
||||
data.warningHeader(s.str());
|
||||
localmap->retypeSymbol(sym,vn->getType()); // use the type propagated into the varnode
|
||||
}
|
||||
// FIXME: Setting the symbol here (for the first time) gives the type no time to propagate properly
|
||||
// Currently the casts aren't set properly
|
||||
|
||||
if (data.attemptDynamicMappingLate(entry, dhash))
|
||||
count += 1;
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -1656,8 +1656,11 @@ SymbolEntry *ScopeInternal::addMapInternal(Symbol *sym,uint4 exfl,const Address
|
|||
list<SymbolEntry>::iterator iter = rangemap->insert(initdata,addr.getOffset(),lastaddress.getOffset());
|
||||
// Store reference to map in symbol
|
||||
sym->mapentry.push_back(iter);
|
||||
if (sym->mapentry.size() == 2)
|
||||
if (sz == sym->type->getSize()) {
|
||||
sym->wholeCount += 1;
|
||||
if (sym->wholeCount == 2)
|
||||
multiEntrySet.insert(sym);
|
||||
}
|
||||
return &(*iter);
|
||||
}
|
||||
|
||||
|
@ -1668,8 +1671,11 @@ SymbolEntry *ScopeInternal::addDynamicMapInternal(Symbol *sym,uint4 exfl,uint8 h
|
|||
list<SymbolEntry>::iterator iter = dynamicentry.end();
|
||||
--iter;
|
||||
sym->mapentry.push_back(iter); // Store reference to map entry in symbol
|
||||
if (sym->mapentry.size() == 2)
|
||||
if (sz == sym->type->getSize()) {
|
||||
sym->wholeCount += 1;
|
||||
if (sym->wholeCount == 2)
|
||||
multiEntrySet.insert(sym);
|
||||
}
|
||||
return &dynamicentry.back();
|
||||
}
|
||||
|
||||
|
@ -1894,7 +1900,7 @@ void ScopeInternal::removeSymbol(Symbol *symbol)
|
|||
list.pop_back();
|
||||
}
|
||||
|
||||
if (symbol->mapentry.size() > 1)
|
||||
if (symbol->wholeCount > 1)
|
||||
multiEntrySet.erase(symbol);
|
||||
// Remove each mapping of the symbol
|
||||
for(iter=symbol->mapentry.begin();iter!=symbol->mapentry.end();++iter) {
|
||||
|
@ -1914,12 +1920,12 @@ void ScopeInternal::renameSymbol(Symbol *sym,const string &newname)
|
|||
|
||||
{
|
||||
nametree.erase(sym); // Erase under old name
|
||||
if (sym->mapentry.size() > 1)
|
||||
if (sym->wholeCount > 1)
|
||||
multiEntrySet.erase(sym); // The multi-entry set is sorted by name, remove
|
||||
string oldname = sym->name;
|
||||
sym->name = newname;
|
||||
insertNameTree(sym);
|
||||
if (sym->mapentry.size() > 1)
|
||||
if (sym->wholeCount > 1)
|
||||
multiEntrySet.insert(sym); // Reenter into the multi-entry set now that name is changed
|
||||
}
|
||||
|
||||
|
@ -1943,6 +1949,7 @@ void ScopeInternal::retypeSymbol(Symbol *sym,Datatype *ct)
|
|||
// Remove the map entry
|
||||
rangemap->erase(iter);
|
||||
sym->mapentry.pop_back(); // Remove reference to map entry
|
||||
sym->wholeCount = 0;
|
||||
|
||||
// Now we are ready to change the type
|
||||
sym->type = ct;
|
||||
|
|
|
@ -167,6 +167,7 @@ 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
|
||||
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
|
||||
void setSymbolId(uint8 val) { symbolId = val; } ///< Assign a unique id to the symbol
|
||||
|
@ -184,10 +185,10 @@ public:
|
|||
};
|
||||
/// \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; }
|
||||
{ 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; }
|
||||
Symbol(Scope *sc) { scope=sc; nameDedup=0; flags=0; dispflags=0; category=-1; symbolId = 0; wholeCount=0; }
|
||||
|
||||
const string &getName(void) const { return name; } ///< Get the local name of the symbol
|
||||
Datatype *getType(void) const { return type; } ///< Get the data-type
|
||||
|
|
|
@ -384,9 +384,10 @@ public:
|
|||
void clearDeadOps(void) { obank.destroyDead(); } ///< Delete any dead PcodeOps
|
||||
Symbol *linkSymbol(Varnode *vn); ///< Find or create Symbol associated with given Varnode
|
||||
Symbol *linkSymbolReference(Varnode *vn); ///< Discover and attach Symbol to a constant reference
|
||||
void findLinkedVarnodes(SymbolEntry *entry,vector<Varnode *> res) const; ///< Find Varnodes that map to the given SymbolEntry
|
||||
void findLinkedVarnodes(SymbolEntry *entry,vector<Varnode *> &res) const; ///< Find Varnodes that map to the given SymbolEntry
|
||||
void buildDynamicSymbol(Varnode *vn); ///< Build a \e dynamic Symbol associated with the given Varnode
|
||||
bool attemptDynamicMapping(SymbolEntry *entry,DynamicHash &dhash);
|
||||
bool attemptDynamicMappingLate(SymbolEntry *entry,DynamicHash &dhash);
|
||||
Merge &getMerge(void) { return covermerge; } ///< Get the Merge object for \b this function
|
||||
|
||||
// op routines
|
||||
|
|
|
@ -27,11 +27,9 @@ void Funcdata::setVarnodeProperties(Varnode *vn) const
|
|||
// One more chance to find entry, now that we know usepoint
|
||||
uint4 vflags=0;
|
||||
SymbolEntry *entry = localmap->queryProperties(vn->getAddr(),vn->getSize(),vn->getUsePoint(*this),vflags);
|
||||
if (entry != (SymbolEntry *)0) { // Let entry try to force type
|
||||
entry->updateType(vn);
|
||||
if (entry->getSymbol()->isTypeLocked())
|
||||
vn->mapentry = entry;
|
||||
}
|
||||
if (entry != (SymbolEntry *)0) // Let entry try to force type
|
||||
vn->setSymbolProperties(entry);
|
||||
else
|
||||
vn->setFlags(vflags & ~Varnode::typelock); // typelock set by updateType
|
||||
}
|
||||
|
||||
|
@ -108,11 +106,9 @@ Varnode *Funcdata::newVarnodeOut(int4 s,const Address &m,PcodeOp *op)
|
|||
|
||||
uint4 vflags = 0;
|
||||
SymbolEntry *entry = localmap->queryProperties(m,s,op->getAddr(),vflags);
|
||||
if (entry != (SymbolEntry *)0) {
|
||||
entry->updateType(vn);
|
||||
if (entry->getSymbol()->isTypeLocked())
|
||||
vn->mapentry = entry;
|
||||
}
|
||||
if (entry != (SymbolEntry *)0)
|
||||
vn->setSymbolProperties(entry);
|
||||
else
|
||||
vn->setFlags(vflags & ~Varnode::typelock); // Typelock set by updateType
|
||||
|
||||
return vn;
|
||||
|
@ -153,11 +149,9 @@ Varnode *Funcdata::newVarnode(int4 s,const Address &m,Datatype *ct)
|
|||
|
||||
uint4 vflags=0;
|
||||
SymbolEntry *entry = localmap->queryProperties(vn->getAddr(),vn->getSize(),Address(),vflags);
|
||||
if (entry != (SymbolEntry *)0) { // Let entry try to force type
|
||||
entry->updateType(vn);
|
||||
if (entry->getSymbol()->isTypeLocked())
|
||||
vn->mapentry = entry;
|
||||
}
|
||||
if (entry != (SymbolEntry *)0) // Let entry try to force type
|
||||
vn->setSymbolProperties(entry);
|
||||
else
|
||||
vn->setFlags(vflags & ~Varnode::typelock); // Typelock set by updateType
|
||||
|
||||
return vn;
|
||||
|
@ -949,34 +943,20 @@ Symbol *Funcdata::linkSymbol(Varnode *vn)
|
|||
Symbol *sym = high->getSymbol();
|
||||
if (sym != (Symbol *)0) return sym; // Symbol already assigned
|
||||
|
||||
entry = vn->getSymbolEntry(); // Check if we have a symbol already cached
|
||||
if (entry == (SymbolEntry *)0) {
|
||||
Address usepoint = vn->getUsePoint(*this);
|
||||
// Find any entry overlapping base address
|
||||
entry = localmap->queryProperties(vn->getAddr(),1,usepoint,flags);
|
||||
if (entry != (SymbolEntry *)0) {
|
||||
entry = localmap->queryProperties(vn->getAddr(), 1, usepoint, flags);
|
||||
if (entry != (SymbolEntry *) 0) {
|
||||
sym = entry->getSymbol();
|
||||
vn->setSymbolEntry(entry);
|
||||
}
|
||||
else { // Must create a symbol entry
|
||||
if (!vn->isPersist()) { // Only create local symbol
|
||||
entry = localmap->addSymbol("",high->getType(),vn->getAddr(),usepoint);
|
||||
entry = localmap->addSymbol("", high->getType(), vn->getAddr(), usepoint);
|
||||
sym = entry->getSymbol();
|
||||
vn->setSymbolEntry(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
sym = entry->getSymbol();
|
||||
if (sym != (Symbol *)0) {
|
||||
int4 offset;
|
||||
if (sym->getCategory() == 1) // For equates we don't care about size
|
||||
offset = -1;
|
||||
else if ((sym->getType()->getSize() == vn->getSize())&&
|
||||
(entry->getAddr() == vn->getAddr())&&(!entry->isPiece())) // A matching entry
|
||||
offset = -1;
|
||||
else
|
||||
offset = vn->getAddr().overlap(0,entry->getAddr(),sym->getType()->getSize()) + entry->getOffset();
|
||||
high->setSymbol(sym,offset);
|
||||
}
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
@ -1006,7 +986,7 @@ Symbol *Funcdata::linkSymbolReference(Varnode *vn)
|
|||
if (entry == (SymbolEntry *)0)
|
||||
return (Symbol *)0;
|
||||
int4 off = (int4)(addr.getOffset() - entry->getAddr().getOffset()) + entry->getOffset();
|
||||
vn->getHigh()->setSymbol(entry->getSymbol(), off);
|
||||
vn->setSymbolReference(entry, off);
|
||||
return entry->getSymbol();
|
||||
}
|
||||
|
||||
|
@ -1014,7 +994,7 @@ Symbol *Funcdata::linkSymbolReference(Varnode *vn)
|
|||
/// add them to the end of the result list.
|
||||
/// \param entry is the given SymbolEntry to match
|
||||
/// \param res is the container holding the result list of matching Varnodes
|
||||
void Funcdata::findLinkedVarnodes(SymbolEntry *entry,vector<Varnode *> res) const
|
||||
void Funcdata::findLinkedVarnodes(SymbolEntry *entry,vector<Varnode *> &res) const
|
||||
|
||||
{
|
||||
if (entry->isDynamic()) {
|
||||
|
@ -1057,7 +1037,7 @@ void Funcdata::buildDynamicSymbol(Varnode *vn)
|
|||
throw RecovError("Unable to find unique hash for varnode");
|
||||
|
||||
Symbol *sym = localmap->addDynamicSymbol("",high->getType(),dhash.getAddress(),dhash.getHash());
|
||||
high->setSymbol(sym,-1);
|
||||
vn->setSymbolEntry(sym->getFirstWholeMap());
|
||||
}
|
||||
|
||||
/// \brief Map properties of a dynamic symbol to a Varnode
|
||||
|
@ -1078,23 +1058,72 @@ bool Funcdata::attemptDynamicMapping(SymbolEntry *entry,DynamicHash &dhash)
|
|||
if (vn == (Varnode *)0) return false;
|
||||
if (entry->getSymbol()->getCategory() == 1) { // Is this an equate symbol
|
||||
if (vn->mapentry != entry) { // Check we haven't marked this before
|
||||
uint4 flags = entry->getAllFlags(); // Mark that the varnode is mapped
|
||||
vn->setFlags(flags & ~Varnode::typelock); // Don't pass data-type and typelock to Varnode
|
||||
vn->mapentry = entry;
|
||||
vn->setSymbolEntry(entry);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (entry->updateType(vn)) {
|
||||
if (entry->getSize() != vn->getSize()) return false;
|
||||
uint4 flags = entry->getAllFlags();
|
||||
vn->setFlags(flags & ~Varnode::typelock); // Mark that the varnode is mapped
|
||||
if (entry->getSymbol()->isTypeLocked())
|
||||
vn->mapentry = entry;
|
||||
else if (entry->getSize() == vn->getSize()) {
|
||||
vn->setSymbolProperties(entry);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Map the name of a dynamic symbol to a Varnode
|
||||
///
|
||||
/// Given a dynamic mapping, try to find the mapped Varnode, then attach the Symbol to the Varnode.
|
||||
/// The name of the Symbol is used, but the data-type and possibly other properties are not
|
||||
/// put on the Varnode.
|
||||
/// \param entry is the (dynamic) Symbol entry
|
||||
/// \param dhash is the dynamic mapping information
|
||||
/// \return \b true if a Varnode was adjusted
|
||||
bool Funcdata::attemptDynamicMappingLate(SymbolEntry *entry,DynamicHash &dhash)
|
||||
|
||||
{
|
||||
dhash.clear();
|
||||
Varnode *vn = dhash.findVarnode(this,entry->getFirstUseAddress(),entry->getHash());
|
||||
if (vn == (Varnode *)0)
|
||||
return false;
|
||||
if (vn->getSymbolEntry() == entry) return false; // Already applied it
|
||||
Symbol *sym = entry->getSymbol();
|
||||
if (vn->getSize() != entry->getSize()) {
|
||||
ostringstream s;
|
||||
s << "Unable to use symbol ";
|
||||
if (!sym->isNameUndefined())
|
||||
s << sym->getName() << ' ';
|
||||
s << ": Size does not match variable it labels";
|
||||
warningHeader(s.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vn->isImplied()) { // This should be finding an explicit, but a cast may have been inserted
|
||||
Varnode *newvn = (Varnode *)0;
|
||||
// Look at the "other side" of the cast
|
||||
if (vn->isWritten() && (vn->getDef()->code() == CPUI_CAST))
|
||||
newvn = vn->getDef()->getIn(0);
|
||||
else {
|
||||
PcodeOp *castop = vn->loneDescend();
|
||||
if ((castop != (PcodeOp *)0)&&(castop->code() == CPUI_CAST))
|
||||
newvn = castop->getOut();
|
||||
}
|
||||
// See if the varnode on the other side is explicit
|
||||
if ((newvn != (Varnode *)0)&&(newvn->isExplicit()))
|
||||
vn = newvn; // in which case we use it
|
||||
}
|
||||
|
||||
vn->setSymbolEntry(entry);
|
||||
if (!sym->isTypeLocked()) { // If the dynamic symbol did not lock its type
|
||||
localmap->retypeSymbol(sym,vn->getType()); // use the type propagated into the varnode
|
||||
}
|
||||
else if (sym->getType() != vn->getType()) {
|
||||
ostringstream s;
|
||||
s << "Unable to use type for symbol " << sym->getName();
|
||||
warningHeader(s.str());
|
||||
localmap->retypeSymbol(sym,vn->getType()); // use the type propagated into the varnode
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \brief Replace all read references to the first Varnode with a second Varnode
|
||||
///
|
||||
/// \param vn is the first Varnode (being replaced)
|
||||
|
|
|
@ -822,13 +822,15 @@ void Merge::mergeMultiEntry(void)
|
|||
int4 conflictCount = 0;
|
||||
for(int4 i=0;i<numEntries;++i) {
|
||||
int4 prevSize = mergeList.size();
|
||||
data.findLinkedVarnodes(symbol->getMapEntry(i), mergeList);
|
||||
SymbolEntry *entry = symbol->getMapEntry(i);
|
||||
if (entry->getSize() != symbol->getType()->getSize())
|
||||
continue;
|
||||
data.findLinkedVarnodes(entry, mergeList);
|
||||
if (mergeList.size() == prevSize)
|
||||
skipCount += 1; // Did not discover any Varnodes corresponding to a particular SymbolEntry
|
||||
}
|
||||
if (mergeList.empty()) continue;
|
||||
HighVariable *high = mergeList[0]->getHigh();
|
||||
Datatype *ct = high->getType();
|
||||
updateHigh(high);
|
||||
for(int4 i=0;i<mergeList.size();++i) {
|
||||
HighVariable *newHigh = mergeList[i]->getHigh();
|
||||
|
@ -1109,7 +1111,7 @@ void Merge::buildDominantCopy(HighVariable *high,vector<PcodeOp *> ©,int4 po
|
|||
}
|
||||
}
|
||||
if (count > 0 && domCopyIsNew) {
|
||||
high->merge(domVn->getHigh(),false);
|
||||
high->merge(domVn->getHigh(),true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,13 +23,56 @@ HighVariable::HighVariable(Varnode *vn)
|
|||
|
||||
{
|
||||
numMergeClasses = 1;
|
||||
highflags = HighVariable::flagsdirty | HighVariable::typedirty | HighVariable::coverdirty;
|
||||
highflags = flagsdirty | typedirty | coverdirty;
|
||||
flags = 0;
|
||||
type = (Datatype *)0;
|
||||
symbol = (Symbol *)0;
|
||||
symboloffset = -1;
|
||||
inst.push_back(vn);
|
||||
vn->setHigh( this, numMergeClasses-1 );
|
||||
if (vn->getSymbolEntry() != (SymbolEntry *)0)
|
||||
setSymbol(vn);
|
||||
}
|
||||
|
||||
/// The given Varnode \b must be a member and \b must have a non-null SymbolEntry
|
||||
void HighVariable::setSymbol(Varnode *vn) const
|
||||
|
||||
{
|
||||
SymbolEntry *entry = vn->getSymbolEntry();
|
||||
if (symbol != (Symbol *)0 && symbol != entry->getSymbol()) {
|
||||
if ((highflags & symboldirty)==0) {
|
||||
ostringstream s;
|
||||
s << "Symbols \"" << symbol->getName() << "\" and \"" << entry->getSymbol()->getName();
|
||||
s << "\" assigned to the same variable";
|
||||
throw LowlevelError(s.str());
|
||||
}
|
||||
}
|
||||
symbol = entry->getSymbol();
|
||||
if (entry->isDynamic()) // Dynamic symbols match whole variable
|
||||
symboloffset = -1;
|
||||
else if (symbol->getCategory() == 1)
|
||||
symboloffset = -1; // For equates, we don't care about size
|
||||
else if (symbol->getType()->getSize() == vn->getSize() &&
|
||||
entry->getAddr() == vn->getAddr() && !entry->isPiece())
|
||||
symboloffset = -1; // A matching entry
|
||||
else
|
||||
symboloffset = vn->getAddr().overlap(0,entry->getAddr(),symbol->getType()->getSize()) + entry->getOffset();
|
||||
|
||||
highflags &= ~((uint4)symboldirty); // We are no longer dirty
|
||||
}
|
||||
|
||||
/// Link information to \b this from a Symbol that is not attached to a member Varnode.
|
||||
/// This only works for a HighVariable with a constant member Varnode. This used when there
|
||||
/// is a constant address reference to the Symbol and the Varnode holds the reference, not
|
||||
/// the actual value of the Symbol.
|
||||
/// \param sym is the given Symbol to attach
|
||||
/// \off is the byte offset into the Symbol of the reference
|
||||
void HighVariable::setSymbolReference(Symbol *sym,int4 off)
|
||||
|
||||
{
|
||||
symbol = sym;
|
||||
symboloffset = off;
|
||||
highflags &= ~((uint4)symboldirty);
|
||||
}
|
||||
|
||||
/// Only update if the cover is marked as \e dirty.
|
||||
|
@ -38,8 +81,8 @@ HighVariable::HighVariable(Varnode *vn)
|
|||
void HighVariable::updateCover(void) const
|
||||
|
||||
{
|
||||
if ((highflags & HighVariable::coverdirty)==0) return; // Cover info is upto date
|
||||
highflags &= ~HighVariable::coverdirty;
|
||||
if ((highflags & coverdirty)==0) return; // Cover info is upto date
|
||||
highflags &= ~coverdirty;
|
||||
|
||||
wholecover.clear();
|
||||
if (!inst[0]->hasCover()) return;
|
||||
|
@ -53,11 +96,11 @@ void HighVariable::updateCover(void) const
|
|||
void HighVariable::updateFlags(void) const
|
||||
|
||||
{
|
||||
vector<Varnode *>::const_iterator iter;
|
||||
uint4 fl;
|
||||
if ((highflags & flagsdirty)==0) return; // flags are up to date
|
||||
|
||||
vector<Varnode *>::const_iterator iter;
|
||||
uint4 fl = 0;
|
||||
|
||||
if ((highflags & HighVariable::flagsdirty)==0) return; // flags are up to date
|
||||
fl = 0;
|
||||
for(iter=inst.begin();iter!=inst.end();++iter)
|
||||
fl |= (*iter)->getFlags();
|
||||
|
||||
|
@ -65,7 +108,7 @@ void HighVariable::updateFlags(void) const
|
|||
flags &= (Varnode::mark | Varnode::typelock);
|
||||
// Update all but these
|
||||
flags |= fl & ~(Varnode::mark | Varnode::directwrite | Varnode::typelock );
|
||||
highflags &= ~HighVariable::flagsdirty; // Clear the dirty flag
|
||||
highflags &= ~flagsdirty; // Clear the dirty flag
|
||||
}
|
||||
|
||||
/// Using Datatype::typeOrder, find the member Varnode with the most specific data-type.
|
||||
|
@ -98,8 +141,8 @@ void HighVariable::updateType(void) const
|
|||
{
|
||||
Varnode *vn;
|
||||
|
||||
if ((highflags&HighVariable::typedirty)==0) return; // Type is up to date
|
||||
highflags &= ~HighVariable::typedirty; // Mark type as clean
|
||||
if ((highflags&typedirty)==0) return; // Type is up to date
|
||||
highflags &= ~typedirty; // Mark type as clean
|
||||
if ((highflags & type_finalized)!=0) return; // Type has been finalized
|
||||
vn = getTypeRepresentative();
|
||||
|
||||
|
@ -110,6 +153,24 @@ void HighVariable::updateType(void) const
|
|||
flags |= Varnode::typelock;
|
||||
}
|
||||
|
||||
void HighVariable::updateSymbol(void) const
|
||||
|
||||
{
|
||||
if ((highflags & symboldirty)==0) return; // flags are up to date
|
||||
highflags &= ~((uint4)symboldirty);
|
||||
vector<Varnode *>::const_iterator iter;
|
||||
symbol = (Symbol *)0;
|
||||
Varnode *vn = (Varnode *)0;
|
||||
|
||||
for(iter=inst.begin();iter!=inst.end();++iter) {
|
||||
Varnode *tmpvn = *iter;
|
||||
if (tmpvn->getSymbolEntry() != (SymbolEntry *)0)
|
||||
vn = tmpvn;
|
||||
}
|
||||
if (vn != (Varnode *)0)
|
||||
setSymbol(vn);
|
||||
}
|
||||
|
||||
/// Compare two Varnode objects based just on their storage address
|
||||
/// \param a is the first Varnode to compare
|
||||
/// \param b is the second Varnode
|
||||
|
@ -193,7 +254,9 @@ void HighVariable::remove(Varnode *vn)
|
|||
for(;iter!=inst.end();++iter) {
|
||||
if (*iter == vn) {
|
||||
inst.erase(iter);
|
||||
highflags |= (HighVariable::flagsdirty|HighVariable::coverdirty|HighVariable::typedirty);
|
||||
highflags |= (flagsdirty|coverdirty|typedirty);
|
||||
if (vn->getSymbolEntry() != (SymbolEntry *)0)
|
||||
highflags |= symboldirty;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -219,12 +282,14 @@ void HighVariable::merge(HighVariable *tv2,bool isspeculative)
|
|||
|
||||
if (tv2 == this) return;
|
||||
|
||||
// if (isAddrTied() && tv2->isAddrTied()) {
|
||||
// if (tied_varnode()->getAddr() != tv2->tied_varnode()->getAddr())
|
||||
// throw LowlevelError("Merging different addrtieds");
|
||||
// }
|
||||
|
||||
highflags |= (HighVariable::flagsdirty|HighVariable::typedirty);
|
||||
highflags |= (flagsdirty|typedirty);
|
||||
if (tv2->symbol != (Symbol *)0) { // Check if we inherit a Symbol
|
||||
if ((tv2->highflags & symboldirty)==0) {
|
||||
symbol = tv2->symbol; // Overwrite our Symbol (assume it is the same)
|
||||
symboloffset = tv2->symboloffset;
|
||||
highflags &= ~((uint4)symboldirty); // Mark that we are not symbol dirty
|
||||
}
|
||||
}
|
||||
|
||||
if (isspeculative) {
|
||||
for(i=0;i<tv2->inst.size();++i) {
|
||||
|
@ -246,10 +311,10 @@ void HighVariable::merge(HighVariable *tv2,bool isspeculative)
|
|||
std::merge(instcopy.begin(),instcopy.end(),tv2->inst.begin(),tv2->inst.end(),inst.begin(),compareJustLoc);
|
||||
tv2->inst.clear();
|
||||
|
||||
if (((highflags&HighVariable::coverdirty)==0)&&((tv2->highflags&HighVariable::coverdirty)==0))
|
||||
if (((highflags&coverdirty)==0)&&((tv2->highflags&coverdirty)==0))
|
||||
wholecover.merge(tv2->wholecover);
|
||||
else
|
||||
highflags |= HighVariable::coverdirty;
|
||||
highflags |= coverdirty;
|
||||
|
||||
delete tv2;
|
||||
}
|
||||
|
|
|
@ -46,11 +46,13 @@ public:
|
|||
flagsdirty = 1, ///< Boolean properties for the HighVariable are dirty
|
||||
typedirty = 2, ///< The data-type for the HighVariable is dirty
|
||||
coverdirty = 4, ///< The cover for the HighVariable is dirty
|
||||
symboldirty = 8, ///< The symbol attachment is dirty
|
||||
copy_in1 = 8, ///< There exists at least 1 COPY into \b this HighVariable from other HighVariables
|
||||
copy_in2 = 16, ///< There exists at least 2 COPYs into \b this HighVariable from other HighVariables
|
||||
type_finalized = 32 ///< Set if a final data-type is locked in and dirtying is disabled
|
||||
};
|
||||
private:
|
||||
friend class Varnode;
|
||||
friend class Merge;
|
||||
vector<Varnode *> inst; ///< The member Varnode objects making up \b this HighVariable
|
||||
int4 numMergeClasses; ///< Number of different speculative merge classes in \b this
|
||||
|
@ -64,34 +66,26 @@ private:
|
|||
void updateFlags(void) const; ///< (Re)derive boolean properties of \b this from the member Varnodes
|
||||
void updateCover(void) const; ///< (Re)derive the cover of \b this from the member Varnodes
|
||||
void updateType(void) const; ///< (Re)derive the data-type for \b this from the member Varnodes
|
||||
void updateSymbol(void) const; ///< (Re)derive the Symbol and offset for \b this from member Varnodes
|
||||
void setCopyIn1(void) const { highflags |= copy_in1; } ///< Mark the existence of one COPY into \b this
|
||||
void setCopyIn2(void) const { highflags |= copy_in2; } ///< Mark the existence of two COPYs into \b this
|
||||
void clearCopyIns(void) const { highflags &= ~(copy_in1 | copy_in2); } ///< Clear marks indicating COPYs into \b this
|
||||
bool hasCopyIn1(void) const { return ((highflags©_in1)!=0); } ///< Is there at least one COPY into \b this
|
||||
bool hasCopyIn2(void) const { return ((highflags©_in2)!=0); } ///< Is there at least two COPYs into \b this
|
||||
void remove(Varnode *vn); ///< Remove a member Varnode from \b this
|
||||
void merge(HighVariable *tv2,bool isspeculative); ///< Merge another HighVariable into \b this
|
||||
public:
|
||||
HighVariable(Varnode *vn); ///< Construct a HighVariable with a single member Varnode
|
||||
Datatype *getType(void) const { updateType(); return type; } ///< Get the data-type
|
||||
|
||||
/// \brief Set the Symbol associated with \b this HighVariable.
|
||||
///
|
||||
/// This HighVariable does not need to be associated with the whole symbol. It can be associated with
|
||||
/// a part, like a sub-field, if the size of the member Varnodes and the Symbol don't match. In this case
|
||||
/// a non-zero offset may be passed in with the Symbol to indicate what part is represented by the \b this.
|
||||
/// \param sym is the Symbol to associate with \b this
|
||||
/// \param off is the offset in bytes, relative to the Symbol, where \b this HighVariable starts
|
||||
void setSymbol(Symbol *sym,int4 off) const {
|
||||
symbol = sym; symboloffset = off; }
|
||||
|
||||
Symbol *getSymbol(void) const { return symbol; } ///< Get the Symbol associated with \b this
|
||||
int4 getSymbolOffset(void) const { return symboloffset; } ///< Get the Symbol offset associated with \b this
|
||||
int4 numInstances(void) const { return inst.size(); } ///< Get the number of member Varnodes \b this has
|
||||
Varnode *getInstance(int4 i) const { return inst[i]; } ///< Get the i-th member Varnode
|
||||
void setSymbol(Varnode *vn) const; ///< Update Symbol information for \b this from the given member Varnode
|
||||
void setSymbolReference(Symbol *sym,int4 off); ///< Attach a reference to a Symbol to \b this
|
||||
void flagsDirty(void) const { highflags |= HighVariable::flagsdirty; } ///< Mark the boolean properties as \e dirty
|
||||
void coverDirty(void) const { highflags |= HighVariable::coverdirty; } ///< Mark the cover as \e dirty
|
||||
void typeDirty(void) const { highflags |= HighVariable::typedirty; } ///< Mark the data-type as \e dirty
|
||||
void remove(Varnode *vn); ///< Remove a member Varnode from \b this
|
||||
public:
|
||||
HighVariable(Varnode *vn); ///< Construct a HighVariable with a single member Varnode
|
||||
Datatype *getType(void) const { updateType(); return type; } ///< Get the data-type
|
||||
Symbol *getSymbol(void) const { updateSymbol(); return symbol; } ///< Get the Symbol associated with \b this
|
||||
int4 getSymbolOffset(void) const { return symboloffset; } ///< Get the Symbol offset associated with \b this
|
||||
int4 numInstances(void) const { return inst.size(); } ///< Get the number of member Varnodes \b this has
|
||||
Varnode *getInstance(int4 i) const { return inst[i]; } ///< Get the i-th member Varnode
|
||||
void finalizeDatatype(Datatype *tp); ///< Set a final datatype for \b this variable
|
||||
|
||||
/// \brief Print details of the cover for \b this (for debug purposes)
|
||||
|
|
|
@ -360,6 +360,46 @@ void Varnode::setDef(PcodeOp *op)
|
|||
setFlags(Varnode::coverdirty|Varnode::written);
|
||||
}
|
||||
|
||||
/// The given Symbol's data-type and flags are inherited by \b this Varnode.
|
||||
/// If the Symbol is \e type-locked, a reference to the Symbol is set on \b this Varnode.
|
||||
/// \param entry is a mapping to the given Symbol
|
||||
void Varnode::setSymbolProperties(SymbolEntry *entry)
|
||||
|
||||
{
|
||||
entry->updateType(this);
|
||||
if (entry->getSymbol()->isTypeLocked()) {
|
||||
mapentry = entry;
|
||||
if (high != (HighVariable *)0)
|
||||
high->setSymbol(this);
|
||||
}
|
||||
setFlags(entry->getAllFlags() & ~Varnode::typelock);
|
||||
}
|
||||
|
||||
/// A reference to the given Symbol is set on \b this Varnode.
|
||||
/// The data-type on \b this Varnode is not changed.
|
||||
/// \param entry is a mapping to the given Symbol
|
||||
void Varnode::setSymbolEntry(SymbolEntry *entry)
|
||||
|
||||
{
|
||||
mapentry = entry;
|
||||
setFlags(Varnode::mapped); // Flags are generally not changed, but we do mark this as mapped
|
||||
if (high != (HighVariable *)0)
|
||||
high->setSymbol(this);
|
||||
}
|
||||
|
||||
/// Link Symbol information to \b this as a \b reference. This only works for a constant Varnode.
|
||||
/// This used when there is a constant address reference to the Symbol and the Varnode holds the
|
||||
/// reference, not the actual value of the Symbol.
|
||||
/// \param entry is a mapping to the given Symbol
|
||||
/// \off is the byte offset into the Symbol of the reference
|
||||
void Varnode::setSymbolReference(SymbolEntry *entry,int4 off)
|
||||
|
||||
{
|
||||
if (high != (HighVariable *)0) {
|
||||
high->setSymbolReference(entry->getSymbol(), off);
|
||||
}
|
||||
}
|
||||
|
||||
/// Change the Datatype and lock state associated with this Varnode if various conditions are met
|
||||
/// - Don't change a previously locked Datatype (unless \b override flag is \b true)
|
||||
/// - Don't consider an \b undefined type to be locked
|
||||
|
@ -394,8 +434,11 @@ void Varnode::copySymbol(const Varnode *vn)
|
|||
mapentry = vn->mapentry; // Copy any symbol
|
||||
flags &= ~(Varnode::typelock | Varnode::namelock);
|
||||
flags |= (Varnode::typelock | Varnode::namelock) & vn->flags;
|
||||
if (high != (HighVariable *)0)
|
||||
if (high != (HighVariable *)0) {
|
||||
high->typeDirty();
|
||||
if (mapentry != (SymbolEntry *)0)
|
||||
high->setSymbol(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// Symbol information (if present) is copied from the given constant Varnode into \b this,
|
||||
|
|
|
@ -154,6 +154,9 @@ private:
|
|||
// These functions should be only private things used by VarnodeBank
|
||||
void setInput(void) { setFlags(Varnode::input|Varnode::coverdirty); } ///< Mark Varnode as \e input
|
||||
void setDef(PcodeOp *op); ///< Set the defining PcodeOp of this Varnode
|
||||
void setSymbolProperties(SymbolEntry *entry); ///< Set properties from the given Symbol to \b this Varnode
|
||||
void setSymbolEntry(SymbolEntry *entry); ///< Attach a Symbol to \b this Varnode
|
||||
void setSymbolReference(SymbolEntry *entry,int4 off); ///< Attach a Symbol reference to \b this
|
||||
void addDescend(PcodeOp *op); ///< Add a descendant (reading) PcodeOp to this Varnode's list
|
||||
void eraseDescend(PcodeOp *op); ///< Erase a descendant (reading) PcodeOp from this Varnode's list
|
||||
void destroyDescend(void); ///< Clear all descendant (reading) PcodeOps
|
||||
|
|
|
@ -31,7 +31,7 @@ import ghidra.xml.XmlPullParser;
|
|||
*/
|
||||
public class HighConstant extends HighVariable {
|
||||
|
||||
private DynamicSymbol symbol;
|
||||
private HighSymbol symbol;
|
||||
private Address pcaddr; // null or Address of PcodeOp which defines the representative
|
||||
|
||||
/**
|
||||
|
@ -94,24 +94,23 @@ public class HighConstant extends HighVariable {
|
|||
restoreInstances(parser, el);
|
||||
pcaddr = function.getPCAddress(represent);
|
||||
if (symref != 0) {
|
||||
HighSymbol sym = function.getLocalSymbolMap().getSymbol(symref);
|
||||
if (sym == null) {
|
||||
sym = function.getGlobalSymbolMap().getSymbol(symref);
|
||||
symbol = function.getLocalSymbolMap().getSymbol(symref);
|
||||
if (symbol == null) {
|
||||
symbol = function.getGlobalSymbolMap().getSymbol(symref);
|
||||
}
|
||||
if (sym instanceof DynamicSymbol) {
|
||||
symbol = (DynamicSymbol) sym;
|
||||
name = sym.getName();
|
||||
sym.setHighVariable(this);
|
||||
if (symbol instanceof DynamicSymbol) {
|
||||
name = symbol.getName();
|
||||
symbol.setHighVariable(this);
|
||||
}
|
||||
else if (sym == null) {
|
||||
else if (symbol == null) {
|
||||
GlobalSymbolMap globalMap = function.getGlobalSymbolMap();
|
||||
Program program = function.getFunction().getProgram();
|
||||
sym = globalMap.populateSymbol(symref, null, -1);
|
||||
if (sym == null) {
|
||||
symbol = globalMap.populateSymbol(symref, null, -1);
|
||||
if (symbol == null) {
|
||||
PcodeOp op = ((VarnodeAST) represent).getLoneDescend();
|
||||
Address addr = HighFunctionDBUtil.getSpacebaseReferenceAddress(program, op);
|
||||
if (addr != null) {
|
||||
sym = globalMap.newSymbol(symref, addr, DataType.DEFAULT, 1);
|
||||
symbol = globalMap.newSymbol(symref, addr, DataType.DEFAULT, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue