More robust Symbol support for HighVariable

This commit is contained in:
caheckman 2019-12-12 16:53:53 -05:00
parent b99772a784
commit cdbee3fe39
11 changed files with 268 additions and 174 deletions

View file

@ -3890,67 +3890,17 @@ 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
count += 1;
if (data.attemptDynamicMappingLate(entry, dhash))
count += 1;
}
return 0;
}

View file

@ -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)
multiEntrySet.insert(sym);
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)
multiEntrySet.insert(sym);
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;

View file

@ -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

View file

@ -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

View file

@ -27,12 +27,10 @@ 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;
}
vn->setFlags(vflags & ~Varnode::typelock); // typelock set by updateType
if (entry != (SymbolEntry *)0) // Let entry try to force type
vn->setSymbolProperties(entry);
else
vn->setFlags(vflags & ~Varnode::typelock); // typelock set by updateType
}
if (vn->cover == (Cover *)0) {
@ -108,12 +106,10 @@ 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;
}
vn->setFlags(vflags & ~Varnode::typelock); // Typelock set by updateType
if (entry != (SymbolEntry *)0)
vn->setSymbolProperties(entry);
else
vn->setFlags(vflags & ~Varnode::typelock); // Typelock set by updateType
return vn;
}
@ -153,12 +149,10 @@ 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;
}
vn->setFlags(vflags & ~Varnode::typelock); // Typelock set by updateType
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,33 +943,19 @@ 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) {
sym = entry->getSymbol();
}
else { // Must create a symbol entry
if (!vn->isPersist()) { // Only create local symbol
entry = localmap->addSymbol("",high->getType(),vn->getAddr(),usepoint);
sym = entry->getSymbol();
}
}
}
else
Address usepoint = vn->getUsePoint(*this);
// Find any entry overlapping base address
entry = localmap->queryProperties(vn->getAddr(), 1, usepoint, flags);
if (entry != (SymbolEntry *) 0) {
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);
vn->setSymbolEntry(entry);
}
else { // Must create a symbol entry
if (!vn->isPersist()) { // Only create local symbol
entry = localmap->addSymbol("", high->getType(), vn->getAddr(), usepoint);
sym = entry->getSymbol();
vn->setSymbolEntry(entry);
}
}
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)

View file

@ -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 *> &copy,int4 po
}
}
if (count > 0 && domCopyIsNew) {
high->merge(domVn->getHigh(),false);
high->merge(domVn->getHigh(),true);
}
}

View file

@ -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;
}

View file

@ -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&copy_in1)!=0); } ///< Is there at least one COPY into \b this
bool hasCopyIn2(void) const { return ((highflags&copy_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)

View file

@ -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,

View file

@ -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

View file

@ -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);
}
}
}