Refactor variable renaming

This commit is contained in:
caheckman 2020-01-09 13:02:10 -05:00
parent b88ea8c927
commit c0dfa509ee
18 changed files with 647 additions and 339 deletions

View file

@ -2332,23 +2332,6 @@ void ActionNameVars::lookForBadJumpTables(Funcdata &data)
}
}
/// From among the \e name \e recommendations (symbol information that wasn't locked)
/// find current symbols for which the name can still apply and apply it.
/// \param data is the function being analyzed
void ActionNameVars::lookForRecommendedNames(Funcdata &data)
{
ScopeLocal *localmap = data.getScopeLocal();
vector<string> names;
vector<Symbol *> symbols;
localmap->makeNameRecommendationsForSymbols(names,symbols);
for(uint4 i=0;i<names.size();++i) {
Symbol *sym = symbols[i];
sym->getScope()->renameSymbol(sym,localmap->makeNameUnique(names[i]));
}
}
/// \brief Add a recommendation to the database based on a particular sub-function parameter.
///
/// We know \b vn holds data-flow for parameter \b param, try to attach its name to \b vn's symbol.
@ -2375,6 +2358,7 @@ void ActionNameVars::makeRec(ProtoParameter *param,Varnode *vn,map<HighVariable
}
HighVariable *high = vn->getHigh();
if (!high->isMark()) return; // Not one of the variables needing a name
if (high->isAddrTied()) return; // Don't propagate parameter name to address tied variable
map<HighVariable *,OpRecommend>::iterator iter = recmap.find(high);
if (iter != recmap.end()) { // We have seen this varnode before
@ -2466,9 +2450,10 @@ void ActionNameVars::linkSpacebaseSymbol(Varnode *vn,Funcdata &data,vector<Varno
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
PcodeOp *op = *iter;
if (op->code() != CPUI_PTRSUB) continue;
Symbol *sym = data.linkSymbolReference(op->getIn(1));
Varnode *offVn = op->getIn(1);
Symbol *sym = data.linkSymbolReference(offVn);
if ((sym != (Symbol *)0) && sym->isNameUndefined())
namerec.push_back(vn);
namerec.push_back(offVn);
}
}
@ -2506,8 +2491,8 @@ void ActionNameVars::linkSymbols(Funcdata &data,vector<Varnode *> &namerec)
if (!high->hasName()) continue;
Symbol *sym = data.linkSymbol(vn);
if (sym != (Symbol *)0) { // Can we associate high with a nameable symbol
if (sym->isNameUndefined())
namerec.push_back(vn);
if (sym->isNameUndefined() && high->getSymbolOffset() < 0)
namerec.push_back(vn); // Add if no name, and we have a high representing the whole
if (sym->isSizeTypeLocked()) {
if (vn->getSize() == sym->getType()->getSize())
sym->getScope()->overrideSizeLockType(sym,high->getType());
@ -2523,33 +2508,21 @@ int4 ActionNameVars::apply(Funcdata &data)
vector<Varnode *> namerec;
linkSymbols(data, namerec);
lookForRecommendedNames(data); // Make sure recommended names hit before subfunc
data.getScopeLocal()->recoverNameRecommendationsForSymbols(); // Make sure recommended names hit before subfunc
lookForBadJumpTables(data);
lookForFuncParamNames(data,namerec);
ScopeLocal *localmap = data.getScopeLocal();
int4 base = 1;
for(uint4 i=0;i<namerec.size();++i) {
Varnode *vn = namerec[i];
HighVariable *high = vn->getHigh();
Symbol *sym = high->getSymbol();
Symbol *sym = vn->getHigh()->getSymbol();
if (sym->isNameUndefined()) {
string newname;
Address usepoint;
if (!vn->isAddrTied())
usepoint = vn->getUsePoint(data);
if (high->isInput()) {
int4 index = -1;
if (sym->getCategory()==0)
index = sym->getCategory()+1;
newname = localmap->buildVariableName(vn->getAddr(),usepoint,high->getType(),index,vn->getFlags());
}
else
newname = localmap->buildVariableName(vn->getAddr(),usepoint,high->getType(),base,vn->getFlags());
sym->getScope()->renameSymbol(sym,newname);
Scope *scope = sym->getScope();
string newname = scope->buildDefaultName(sym, base, vn);
scope->renameSymbol(sym,newname);
}
}
data.getScopeLocal()->assignDefaultNames(base);
return 0;
}

View file

@ -463,7 +463,6 @@ class ActionNameVars : public Action {
};
static void makeRec(ProtoParameter *param,Varnode *vn,map<HighVariable *,OpRecommend> &recmap);
static void lookForBadJumpTables(Funcdata &data); ///< Mark the switch variable for bad jump-tables
static void lookForRecommendedNames(Funcdata &data); ///< Try to apply names from unlocked symbols
static void lookForFuncParamNames(Funcdata &data,const vector<Varnode *> &varlist);
static void linkSpacebaseSymbol(Varnode *vn,Funcdata &data,vector<Varnode *> &namerec);
static void linkSymbols(Funcdata &data,vector<Varnode *> &namerec);

View file

@ -1641,6 +1641,45 @@ Symbol *Scope::addDynamicSymbol(const string &nm,Datatype *ct,const Address &cad
return sym;
}
/// Create default name given information in the Symbol and possibly a representative Varnode.
/// This method extracts the crucial properties and then uses the buildVariableName method to
/// construct the actual name.
/// \param sym is the given Symbol to name
/// \param base is an index (which may get updated) used to uniquify the name
/// \param vn is an optional (may be null) Varnode representative of the Symbol
/// \return the default name
string Scope::buildDefaultName(Symbol *sym,int4 &base,Varnode *vn) const
{
if (vn != (Varnode *)0 && !vn->isConstant()) {
Address usepoint;
if (!vn->isAddrTied() && fd != (Funcdata *)0)
usepoint = vn->getUsePoint(*fd);
HighVariable *high = vn->getHigh();
if (sym->getCategory() == 0 || high->isInput()) {
int4 index = -1;
if (sym->getCategory()==0)
index = sym->getCategoryIndex()+1;
return buildVariableName(vn->getAddr(),usepoint,sym->getType(),index,vn->getFlags() | Varnode::input);
}
return buildVariableName(vn->getAddr(),usepoint,sym->getType(),base,vn->getFlags());
}
if (sym->numEntries() != 0) {
SymbolEntry *entry = sym->getMapEntry(0);
Address addr = entry->getAddr();
Address usepoint = entry->getFirstUseAddress();
uint4 flags = usepoint.isInvalid() ? Varnode::addrtied : 0;
if (sym->getCategory() == 0) { // If this is a parameter
flags |= Varnode::input;
int4 index = sym->getCategoryIndex() + 1;
return buildVariableName(addr, usepoint, sym->getType(), index, flags);
}
return buildVariableName(addr, usepoint, sym->getType(), base, flags);
}
// Should never reach here
return buildVariableName(Address(), Address(), sym->getType(), base, 0);
}
/// \brief Is the given memory range marked as \e read-only
///
/// Check for Symbols relative to \b this Scope that are marked as \e read-only,
@ -1943,18 +1982,11 @@ void ScopeInternal::clearUnlockedCategory(int4 cat)
}
}
void ScopeInternal::removeSymbol(Symbol *symbol)
void ScopeInternal::removeSymbolMappings(Symbol *symbol)
{
vector<list<SymbolEntry>::iterator>::iterator iter;
if (symbol->category >= 0) {
vector<Symbol *> &list(category[symbol->category]);
list[symbol->catindex] = (Symbol *)0;
while((!list.empty())&&(list.back() == (Symbol *)0))
list.pop_back();
}
if (symbol->wholeCount > 1)
multiEntrySet.erase(symbol);
// Remove each mapping of the symbol
@ -1967,6 +1999,20 @@ void ScopeInternal::removeSymbol(Symbol *symbol)
rangemap->erase( *iter );
}
}
symbol->wholeCount = 0;
symbol->mapentry.clear();
}
void ScopeInternal::removeSymbol(Symbol *symbol)
{
if (symbol->category >= 0) {
vector<Symbol *> &list(category[symbol->category]);
list[symbol->catindex] = (Symbol *)0;
while((!list.empty())&&(list.back() == (Symbol *)0))
list.pop_back();
}
removeSymbolMappings(symbol);
nametree.erase(symbol);
delete symbol;
}
@ -2654,6 +2700,26 @@ void ScopeInternal::setCategory(Symbol *sym,int4 cat,int4 ind)
list[sym->catindex] = sym;
}
/// Run through all the symbols whose name is undefined. Build a variable name, uniquify it, and
/// rename the variable.
/// \param base is the base index to start at for generating generic names
void ScopeInternal::assignDefaultNames(int4 &base)
{
SymbolNameTree::const_iterator iter;
Symbol testsym((Scope *)0,"$$undef",(Datatype *)0);
iter = nametree.upper_bound(&testsym);
while(iter != nametree.end()) {
Symbol *sym = *iter;
if (!sym->isNameUndefined()) break;
++iter; // Advance before renaming
string nm = buildDefaultName(sym, base, (Varnode *)0);
renameSymbol(sym, nm);
}
}
/// Check to make sure the Scope is a \e namespace then remove all
/// its address ranges from the map.
/// \param scope is the given Scope

View file

@ -170,7 +170,6 @@ protected:
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
void checkSizeTypeLock(void); ///< Calculate if \b size_typelock property is on
public:
/// \brief Possible display (dispflag) properties for a Symbol
@ -495,6 +494,7 @@ protected:
virtual SymbolEntry *addDynamicMapInternal(Symbol *sym,uint4 exfl,uint8 hash,int4 off,int4 sz,
const RangeList &uselim)=0;
SymbolEntry *addMap(const SymbolEntry &entry); ///< Integrate a SymbolEntry into the range maps
void setSymbolId(Symbol *sym,uint8 id) const { sym->symbolId = id; } ///< Adjust the id associated with a symbol
public:
#ifdef OPACTION_DEBUG
mutable bool debugon;
@ -531,6 +531,7 @@ public:
virtual bool inScope(const Address &addr,int4 size, const Address &usepoint) const {
return rangetree.inRange(addr,size); }
virtual void removeSymbolMappings(Symbol *symbol)=0; ///< Remove all SymbolEntrys from the given Symbol
virtual void removeSymbol(Symbol *symbol)=0; ///< Remove the given Symbol from \b this Scope
virtual void renameSymbol(Symbol *sym,const string &newname)=0; ///< Rename a Symbol within \b this Scope
@ -706,6 +707,7 @@ public:
ExternRefSymbol *addExternalRef(const Address &addr,const Address &refaddr,const string &nm);
LabSymbol *addCodeLabel(const Address &addr,const string &nm);
Symbol *addDynamicSymbol(const string &nm,Datatype *ct,const Address &caddr,uint8 hash);
string buildDefaultName(Symbol *sym,int4 &base,Varnode *vn) const; ///< Create a default name for the given Symbol
bool isReadOnly(const Address &addr,int4 size,const Address &usepoint) const;
void printBounds(ostream &s) const { rangetree.printBounds(s); } ///< Print a description of \b this Scope's \e owned memory ranges
};
@ -745,6 +747,7 @@ public:
virtual list<SymbolEntry>::const_iterator endDynamic(void) const;
virtual list<SymbolEntry>::iterator beginDynamic(void);
virtual list<SymbolEntry>::iterator endDynamic(void);
virtual void removeSymbolMappings(Symbol *symbol);
virtual void removeSymbol(Symbol *symbol);
virtual void renameSymbol(Symbol *sym,const string &newname);
virtual void retypeSymbol(Symbol *sym,Datatype *ct);
@ -777,6 +780,7 @@ public:
virtual int4 getCategorySize(int4 cat) const;
virtual Symbol *getCategorySymbol(int4 cat,int4 ind) const;
virtual void setCategory(Symbol *sym,int4 cat,int4 ind);
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

View file

@ -101,6 +101,7 @@ public:
virtual void clearUnlockedCategory(int4 cat) { throw LowlevelError("clearUnlockedCategory unimplemented"); }
virtual void clearUnlocked(void) { throw LowlevelError("clearUnlocked unimplemented"); }
virtual void restrictScope(Funcdata *f) { throw LowlevelError("restrictScope unimplemented"); }
virtual void removeSymbolMappings(Symbol *symbol) { throw LowlevelError("removeSymbolMappings unimplemented"); }
virtual void removeSymbol(Symbol *symbol) { throw LowlevelError("removeSymbol unimplemented"); }
virtual void renameSymbol(Symbol *sym,const string &newname) { throw LowlevelError("renameSymbol unimplemented"); }
virtual void retypeSymbol(Symbol *sym,Datatype *ct) { throw LowlevelError("retypeSymbol unimplemented"); }

View file

@ -2478,14 +2478,7 @@ ProtoParameter *ProtoStoreSymbol::setInput(int4 i, const string &nm,const Parame
if (res->sym == (Symbol *)0) {
if (scope->discoverScope(pieces.addr,pieces.type->getSize(),usepoint) != scope)
usepoint = restricted_usepoint;
string name;
if (nm.size()==0) {
int4 index = i+1;
name = scope->buildVariableName(pieces.addr,usepoint,pieces.type,index,Varnode::input);
}
else
name = nm;
res->sym = scope->addSymbol(name,pieces.type,pieces.addr,usepoint)->getSymbol();
res->sym = scope->addSymbol(nm,pieces.type,pieces.addr,usepoint)->getSymbol();
scope->setCategory(res->sym,0,i);
if ((pieces.flags & (Varnode::indirectstorage|Varnode::hiddenretparm)) != 0)
scope->setAttribute(res->sym,pieces.flags & (Varnode::indirectstorage|Varnode::hiddenretparm));

View file

@ -362,6 +362,7 @@ public:
bool ancestorOpUse(int4 maxlevel,const Varnode *invn,const PcodeOp *op,ParamTrial &trial) const;
bool syncVarnodesWithSymbols(const ScopeLocal *lm,bool typesyes);
void transferVarnodeProperties(Varnode *vn,Varnode *newVn,int4 lsbOffset);
void splitVarnode(Varnode *vn,int4 lowsize,Varnode *&vnlo,Varnode *& vnhi);
bool fillinReadOnly(Varnode *vn); ///< Replace the given Varnode with its (constant) value in the load image
bool replaceVolatile(Varnode *vn); ///< Replace accesses of the given Varnode with \e volatile operations
void markIndirectOnly(void); ///< Mark \e illegal \e input Varnodes used only in INDIRECTs
@ -382,8 +383,12 @@ public:
void clearDeadVarnodes(void); ///< Delete any dead Varnodes
void calcNZMask(void); ///< Calculate \e non-zero masks for all Varnodes
void clearDeadOps(void) { obank.destroyDead(); } ///< Delete any dead PcodeOps
void clearSymbolLinks(HighVariable *high); ///< Clear Symbols attached to Varnodes in the given HighVariable
void remapVarnode(Varnode *vn,Symbol *sym,const Address &usepoint);
void remapDynamicVarnode(Varnode *vn,Symbol *sym,const Address &usepoint,uint8 hash);
Symbol *linkSymbol(Varnode *vn); ///< Find or create Symbol associated with given Varnode
Symbol *linkSymbolReference(Varnode *vn); ///< Discover and attach Symbol to a constant reference
Varnode *findLinkedVarnode(SymbolEntry *entry) const; ///< Find a Varnode matching the given Symbol mapping
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);

View file

@ -307,26 +307,10 @@ HighVariable *Funcdata::findHigh(const string &name) const
localmap->queryByName(name,symList);
if (symList.empty()) return (HighVariable *)0;
Symbol *sym = symList[0];
SymbolEntry *entry = sym->getFirstWholeMap();
if (entry->isDynamic()) {
DynamicHash dhash;
Varnode *vn = dhash.findVarnode(this, entry->getFirstUseAddress(), entry->getHash());
if (vn == (Varnode *)0 || vn->isAnnotation())
return (HighVariable *)0;
Varnode *vn = findLinkedVarnode(sym->getFirstWholeMap());
if (vn != (Varnode *)0)
return vn->getHigh();
}
VarnodeLocSet::const_iterator iter,enditer;
HighVariable *high;
iter = vbank.beginLoc(entry->getSize(),entry->getAddr());
enditer = vbank.endLoc(entry->getSize(),entry->getAddr());
for(;iter!=enditer;++iter) {
high = (*iter)->getHigh();
if (high->getSymbol() == sym)
return high;
}
return (HighVariable *)0;
}
@ -929,6 +913,49 @@ bool Funcdata::syncVarnodesWithSymbol(VarnodeLocSet::const_iterator &iter,uint4
return updateoccurred;
}
/// For each instance Varnode, remove any SymbolEntry reference and associated properties.
/// \param high is the given HighVariable to clear
void Funcdata::clearSymbolLinks(HighVariable *high)
{
for(int4 i=0;i<high->numInstances();++i) {
Varnode *vn = high->getInstance(i);
vn->mapentry = (SymbolEntry *)0;
vn->clearFlags(Varnode::namelock | Varnode::typelock | Varnode::mapped);
}
}
/// \brief Remap a Symbol to a given Varnode using a static mapping
///
/// Any previous links between the Symbol, the Varnode, and the associate HighVariable are
/// removed. Then a new link is created.
/// \param vn is the given Varnode
/// \param sym is the Symbol the Varnode maps to
/// \param usepoint is the desired usepoint for the mapping
void Funcdata::remapVarnode(Varnode *vn,Symbol *sym,const Address &usepoint)
{
clearSymbolLinks(vn->getHigh());
SymbolEntry *entry = localmap->remapSymbol(sym, vn->getAddr(), usepoint);
vn->setSymbolEntry(entry);
}
/// \brief Remap a Symbol to a given Varnode using a new dynamic mapping
///
/// Any previous links between the Symbol, the Varnode, and the associate HighVariable are
/// removed. Then a new dynamic link is created.
/// \param vn is the given Varnode
/// \param sym is the Symbol the Varnode maps to
/// \param usepoint is the code Address where the Varnode is defined
/// \param hash is the hash for the new dynamic mapping
void Funcdata::remapDynamicVarnode(Varnode *vn,Symbol *sym,const Address &usepoint,uint8 hash)
{
clearSymbolLinks(vn->getHigh());
SymbolEntry *entry = localmap->remapSymbolDynamic(sym, hash, usepoint);
vn->setSymbolEntry(entry);
}
/// The Symbol is really attached to the Varnode's HighVariable (which must exist).
/// The only reason a Symbol doesn't get set is if, the HighVariable
/// is global and there is no pre-existing Symbol. (see mapGlobals())
@ -990,6 +1017,44 @@ Symbol *Funcdata::linkSymbolReference(Varnode *vn)
return entry->getSymbol();
}
/// Return the (first) Varnode that matches the given SymbolEntry
/// \param entry is the given SymbolEntry
/// \return a matching Varnode or null
Varnode *Funcdata::findLinkedVarnode(SymbolEntry *entry) const
{
if (entry->isDynamic()) {
DynamicHash dhash;
Varnode *vn = dhash.findVarnode(this, entry->getFirstUseAddress(), entry->getHash());
if (vn == (Varnode *)0 || vn->isAnnotation())
return (Varnode *)0;
return vn;
}
VarnodeLocSet::const_iterator iter,enditer;
Address usestart = entry->getFirstUseAddress();
enditer = vbank.endLoc(entry->getSize(),entry->getAddr());
if (usestart.isInvalid()) {
iter = vbank.beginLoc(entry->getSize(),entry->getAddr());
if (iter == enditer)
return (Varnode *)0;
Varnode *vn = *iter;
if (!vn->isAddrTied())
return (Varnode *)0; // Varnode(s) must be address tied in order to match this symbol
return vn;
}
iter = vbank.beginLoc(entry->getSize(),entry->getAddr(),usestart,~((uintm)0));
// TODO: Use a better end iterator
for(;iter!=enditer;++iter) {
Varnode *vn = *iter;
Address usepoint = vn->getUsePoint(*this);
if (entry->inUse(usepoint))
return vn;
}
return (Varnode *)0;
}
/// Look for Varnodes that are (should be) mapped to the given SymbolEntry and
/// add them to the end of the result list.
/// \param entry is the given SymbolEntry to match

View file

@ -16,39 +16,6 @@
#include "varmap.hh"
#include "funcdata.hh"
/// \param ad is the storage address of the variable
/// \param use is the use point address in code
/// \param sz is the optional size of the variable
AddressUsePointPair::AddressUsePointPair(const Address &ad,const Address &use,int4 sz) : addr(ad), useaddr(use)
{
size = sz;
if (useaddr.isInvalid()) // If invalid
useaddr = Address((AddrSpace *)0,0); // Make sure to set offset to zero, so invalids compare equal
}
/// Compare first by storage address and then by use point address.
/// Do NOT compare the optional size.
/// \param op2 is the pair to compare to \b this
/// \return \b true if \b this should be sorted first
bool AddressUsePointPair::operator<(const AddressUsePointPair &op2) const
{
if (addr != op2.addr)
return (addr < op2.addr);
return (useaddr < op2.useaddr);
}
/// Storage addresses and use point addresses must match. Size does not have to match.
/// \param op2 is the pair to test \b this against for equality
/// \return \b true if \b the two pairs are equal
bool AddressUsePointPair::operator==(const AddressUsePointPair &op2) const
{
if (addr != op2.addr) return false;
return (useaddr == op2.useaddr);
}
/// \brief Can the given intersecting RangeHint coexist with \b this at their given offsets
///
/// Determine if the data-type information in the two ranges \e line \e up
@ -321,22 +288,7 @@ void ScopeLocal::collectNameRecs(void)
while(iter!=nametree.end()) {
Symbol *sym = *iter++;
if (sym->isNameLocked()&&(!sym->isTypeLocked())) {
SymbolEntry *entry = sym->getFirstWholeMap();
if (entry != (SymbolEntry *)0) {
if (entry->isDynamic()) {
addDynamicRecommend(entry->getFirstUseAddress(), entry->getHash(), sym->getName());
}
else {
Address usepoint;
if (!entry->getUseLimit().empty()) {
const Range *range = entry->getUseLimit().getFirstRange();
usepoint = Address(range->getSpace(),range->getFirst());
}
addRecommendName( entry->getAddr(), usepoint, sym->getName(), entry->getSize() );
}
if (sym->getCategory()<0)
removeSymbol(sym);
}
addRecommendName(sym);
}
}
}
@ -446,12 +398,6 @@ string ScopeLocal::buildVariableName(const Address &addr,
Datatype *ct,
int4 &index,uint4 flags) const
{
map<AddressUsePointPair,string>::const_iterator iter;
iter = nameRecommend.find( AddressUsePointPair(addr,pc,0));
if (iter != nameRecommend.end()) {
// We are not checking if the recommended size matches
return makeNameUnique((*iter).second);
}
if (((flags & (Varnode::addrtied|Varnode::persist))==Varnode::addrtied) &&
addr.getSpace() == space) {
if (fd->getFuncProto().getLocalRange().inRange(addr,1)) {
@ -520,10 +466,7 @@ void ScopeLocal::createEntry(const RangeHint &a)
if (num>1)
ct = glb->types->getTypeArray(num,ct);
int4 index=0;
string nm = buildVariableName(addr,usepoint,ct,index,Varnode::addrtied);
addSymbol(nm,ct,addr,usepoint);
addSymbol("",ct,addr,usepoint);
}
/// Set up basic offset boundaries for what constitutes a local variable
@ -1220,10 +1163,8 @@ void ScopeLocal::fakeInputSymbols(void)
int4 size = (endpoint - addr.getOffset()) + 1;
Datatype *ct = fd->getArch()->types->getBase(size,TYPE_UNKNOWN);
int4 index = -1; // NOT a parameter
string nm = buildVariableName(addr,usepoint,ct,index,Varnode::input);
try {
addSymbol(nm,ct,addr,usepoint)->getSymbol();
addSymbol("",ct,addr,usepoint)->getSymbol();
}
catch(LowlevelError &err) {
fd->warningHeader(err.explain);
@ -1233,48 +1174,95 @@ void ScopeLocal::fakeInputSymbols(void)
}
}
/// \brief Try to pick recommended names for any unnamed Symbols
/// \brief Change the primary mapping for the given Symbol to be a specific storage address and use point
///
/// Remove any other mapping and create a mapping based on the given storage.
/// \param sym is the given Symbol to remap
/// \param addr is the starting address of the storage
/// \param usepoint is the use point for the mapping
/// \return the new mapping
SymbolEntry *ScopeLocal::remapSymbol(Symbol *sym,const Address &addr,const Address &usepoint)
{
SymbolEntry *entry = sym->getFirstWholeMap();
int4 size = entry->getSize();
if (!entry->isDynamic()) {
if (entry->getAddr() == addr && entry->getFirstUseAddress() == usepoint)
return entry;
}
removeSymbolMappings(sym);
RangeList rnglist;
if (!usepoint.isInvalid())
rnglist.insertRange(usepoint.getSpace(),usepoint.getOffset(),usepoint.getOffset());
return addMapInternal(sym,Varnode::mapped,addr,0,size,rnglist);
}
/// \brief Make the primary mapping for the given Symbol, dynamic
///
/// Remove any other mapping and create a new dynamic mapping based on a given
/// size and hash
/// \param sym is the given Symbol to remap
/// \param hash is the dynamic hash
/// \param usepoint is the use point for the mapping
/// \return the new dynamic mapping
SymbolEntry *ScopeLocal::remapSymbolDynamic(Symbol *sym,uint8 hash,const Address &usepoint)
{
SymbolEntry *entry = sym->getFirstWholeMap();
int4 size = entry->getSize();
if (entry->isDynamic()) {
if (entry->getHash() == hash && entry->getFirstUseAddress() == usepoint)
return entry;
}
removeSymbolMappings(sym);
RangeList rnglist;
if (!usepoint.isInvalid())
rnglist.insertRange(usepoint.getSpace(),usepoint.getOffset(),usepoint.getOffset());
return addDynamicMapInternal(sym,Varnode::mapped,hash,0,size,rnglist);
}
/// \brief Run through name recommendations, checking if any match unnamed symbols
///
/// Unlocked symbols that are presented to the decompiler are stored off as \e recommended names. These
/// can be reattached after the decompiler makes a determination of what the final Symbols are.
/// This method runs through the recommended names and checks if they can be applied to an existing
/// unnamed Symbol.
/// \param resname will hold the new name strings
/// \param ressym will hold the list of Symbols corresponding to the new name strings
void ScopeLocal::makeNameRecommendationsForSymbols(vector<string> &resname,vector<Symbol *> &ressym) const
void ScopeLocal::recoverNameRecommendationsForSymbols(void)
{ // Find nameable symbols with a varnode rep matching a name recommendation
map<AddressUsePointPair,string>::const_iterator iter;
{
list<NameRecommend>::const_iterator iter;
for(iter=nameRecommend.begin();iter!=nameRecommend.end();++iter) {
VarnodeLocSet::const_iterator biter,eiter;
bool isaddrtied;
const Address &addr((*iter).first.getAddr());
const Address &useaddr((*iter).first.getUseAddr());
int4 size = (*iter).first.getSize();
if (useaddr.isInvalid()) {
isaddrtied = true;
biter = fd->beginLoc(size,addr);
eiter = fd->endLoc(size,addr);
const Address &addr((*iter).getAddr());
const Address &usepoint((*iter).getUseAddr());
int4 size = (*iter).getSize();
Symbol *sym;
Varnode *vn = (Varnode *)0;
if (usepoint.isInvalid()) {
SymbolEntry *entry = findOverlap(addr, size); // Recover any Symbol regardless of usepoint
if (entry == (SymbolEntry *)0) continue;
if (entry->getAddr() != addr) // Make sure Symbol has matching address
continue;
sym = entry->getSymbol();
if ((sym->getFlags() & Varnode::addrtied)==0)
continue; // Symbol must be address tied to match this name recommendation
vn = fd->findLinkedVarnode(entry);
}
else {
isaddrtied = false;
biter = fd->beginLoc(size,addr,useaddr);
eiter = fd->endLoc(size,addr,useaddr);
vn = fd->findVarnodeWritten(size,addr,usepoint);
if (vn == (Varnode *)0) continue;
sym = vn->getHigh()->getSymbol();
if (sym == (Symbol *)0) continue;
SymbolEntry *entry = sym->getFirstWholeMap();
if (entry->getAddr() != addr)
continue;
if (entry->getSize() != size) continue;
}
while(biter != eiter) {
Varnode *vn = *biter;
if (!vn->isAnnotation()) {
Symbol *sym = vn->getHigh()->getSymbol();
if (sym != (Symbol *)0) {
if (sym->isNameUndefined()) {
resname.push_back( (*iter).second);
ressym.push_back(sym);
break;
}
}
}
if (isaddrtied) break;
++biter;
if (!sym->isNameUndefined()) continue;
renameSymbol(sym,makeNameUnique((*iter).getName()));
setSymbolId(sym, (*iter).getSymbolId());
setAttribute(sym, Varnode::namelock);
if (vn != (Varnode *)0) {
fd->remapVarnode(vn, sym, usepoint);
}
}
@ -1289,38 +1277,36 @@ void ScopeLocal::makeNameRecommendationsForSymbols(vector<string> &resname,vecto
if (vn == (Varnode *)0) continue;
if (vn->isAnnotation()) continue;
Symbol *sym = vn->getHigh()->getSymbol();
if (sym != (Symbol *)0) {
if (sym->isNameUndefined()) {
resname.push_back( dynEntry.getName() );
ressym.push_back(sym);
}
}
if (sym == (Symbol *)0) continue;
if (sym->getScope() != this) continue;
if (!sym->isNameUndefined()) continue;
renameSymbol(sym,makeNameUnique( dynEntry.getName() ));
setAttribute(sym, Varnode::namelock);
setSymbolId(sym, dynEntry.getSymbolId());
fd->remapDynamicVarnode(vn, sym, dynEntry.getAddress(), dynEntry.getHash());
}
}
/// \brief Add a new recommended name to the list
///
/// Recommended names are associated with a storage address, a use point, and a suggested size.
/// The symbol is stored as a name recommendation and then removed from the scope.
/// Name recommendations are associated either with a storage address and usepoint, or a dynamic hash.
/// The name may be reattached to a Symbol after decompilation.
/// \param addr is the storage address
/// \param usepoint is the address of the code use point
/// \param nm is the recommended name
/// \param sz is the suggested size the Symbol should match
void ScopeLocal::addRecommendName(const Address &addr,const Address &usepoint,const string &nm,int4 sz)
/// \param sym is the given Symbol to treat as a name recommendation
void ScopeLocal::addRecommendName(Symbol *sym)
{
nameRecommend[ AddressUsePointPair(addr,usepoint,sz) ] = nm;
}
/// \brief Add a new recommended name for a dynamic storage location to the list
///
/// This recommended name is assigned a storage location via the DynamicHash mechanism.
/// The name may be reattached to a Symbol after decompilation.
/// \param addr is the address of the code use point
/// \param hash is the hash encoding context for identifying the storage location
/// \param nm is the recommended name
void ScopeLocal::addDynamicRecommend(const Address &usepoint,uint8 hash,const string &nm)
{
dynRecommend.push_back(DynamicRecommend(usepoint,hash,nm));
SymbolEntry *entry = sym->getFirstWholeMap();
if (entry == (SymbolEntry *) 0) return;
if (entry->isDynamic()) {
dynRecommend.push_back(DynamicRecommend(entry->getFirstUseAddress(), entry->getHash(), sym->getName(), sym->getId()));
}
else {
Address usepoint;
if (!entry->getUseLimit().empty()) {
const Range *range = entry->getUseLimit().getFirstRange();
usepoint = Address(range->getSpace(), range->getFirst());
}
nameRecommend.push_back(NameRecommend(entry->getAddr(),usepoint, entry->getSize(), sym->getName(), sym->getId()));
}
if (sym->getCategory() < 0)
removeSymbol(sym);
}

View file

@ -21,23 +21,20 @@
#include "database.hh"
/// \brief An Address pair with a point of use
///
/// A storage location and a point in the code where the storage is referenced.
/// This object sorts first based on the storage address then on the use point.
class AddressUsePointPair {
class NameRecommend {
Address addr; ///< The starting address of the storage location
Address useaddr; ///< The code address at the point of use
int4 size; ///< An optional/recommended size for the variable being stored
string name; ///< The local symbol name recommendation
uint8 symbolId; ///< Id associated with the original Symbol
public:
AddressUsePointPair(const Address &ad,const Address &use,int4 sz); ///< Constructor
AddressUsePointPair(const AddressUsePointPair &op2) : addr(op2.addr), useaddr(op2.useaddr) {
size = op2.size; } ///< Copy constructor
NameRecommend(const Address &ad,const Address &use,int4 sz,const string &nm,uint8 id) :
addr(ad), useaddr(use), size(sz), name(nm), symbolId(id) {} ///< Constructor
const Address &getAddr(void) const { return addr; } ///< Get the storage address
const Address &getUseAddr(void) const { return useaddr; } ///< Get the use point address
int4 getSize(void) const { return size; } ///< Get the optional size
bool operator<(const AddressUsePointPair &op2) const; ///< Compare operation
bool operator==(const AddressUsePointPair &op2) const; ///< Test for equality
string getName(void) const { return name; } ///< Get the recommended name
uint8 getSymbolId(void) const { return symbolId; } ///< Get the original Symbol id
};
/// \brief A name recommendation for a particular dynamic location
@ -48,15 +45,14 @@ class DynamicRecommend {
Address usePoint; ///< Use point of the Symbol
uint8 hash; ///< Hash encoding the Symbols environment
string name; ///< The local symbol name recommendation
uint8 symbolId; ///< Id associated with the original Symbol
public:
DynamicRecommend(const Address &addr,uint8 h,const string &nm) :
usePoint(addr) {
hash = h;
name = nm;
} ///< Constructor
DynamicRecommend(const Address &addr,uint8 h,const string &nm,uint8 id) :
usePoint(addr), hash(h), name(nm), symbolId(id) {} ///< Constructor
const Address &getAddress(void) const { return usePoint; } ///< Get the use point address
uint8 getHash(void) const { return hash; } ///< Get the dynamic hash
string getName(void) const { return name; } ///< Get the recommended name
uint8 getSymbolId(void) const { return symbolId; } ///< Get the original Symbol id
};
/// \brief Partial data-type information mapped to a specific range of bytes
@ -181,7 +177,7 @@ public:
class ScopeLocal : public ScopeInternal {
AddrSpace *space; ///< Address space containing the local stack
RangeList localRange; ///< The set of addresses that might hold mapped locals (not parameters)
map<AddressUsePointPair,string> nameRecommend; ///< Symbol name recommendations for specific addresses
list<NameRecommend> nameRecommend; ///< Symbol name recommendations for specific addresses
list<DynamicRecommend> dynRecommend; ///< Symbol name recommendations for dynamic locations
bool stackGrowsNegative; ///< Marked \b true if the stack is considered to \e grow towards smaller offsets
bool rangeLocked; ///< True if the subset of addresses \e mapped to \b this scope has been locked
@ -190,8 +186,7 @@ class ScopeLocal : public ScopeInternal {
bool restructure(MapState &state); ///< Merge hints into a formal Symbol layout of the address space
void markUnaliased(const vector<uintb> &alias); ///< Mark all local symbols for which there are no aliases
void fakeInputSymbols(void); ///< Make sure all stack inputs have an associated Symbol
void addRecommendName(const Address &addr,const Address &usepoint,const string &nm,int4 sz);
void addDynamicRecommend(const Address &usepoint,uint8 hash,const string &nm);
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
@ -217,7 +212,9 @@ public:
void resetLocalWindow(void); ///< Reset the set of addresses that are considered mapped by the scope to the default
void restructureVarnode(bool aliasyes); ///< Layout mapped symbols based on Varnode information
void restructureHigh(void); ///< Layout mapped symbols based on HighVariable information
void makeNameRecommendationsForSymbols(vector<string> &resname,vector<Symbol *> &ressym) const;
SymbolEntry *remapSymbol(Symbol *sym,const Address &addr,const Address &usepoint);
SymbolEntry *remapSymbolDynamic(Symbol *sym,uint8 hash,const Address &usepoint);
void recoverNameRecommendationsForSymbols(void);
};
#endif

View file

@ -382,7 +382,10 @@ void Varnode::setSymbolEntry(SymbolEntry *entry)
{
mapentry = entry;
setFlags(Varnode::mapped); // Flags are generally not changed, but we do mark this as mapped
uint4 fl = Varnode::mapped; // Flags are generally not changed, but we do mark this as mapped
if (entry->getSymbol()->isNameLocked())
fl |= Varnode::namelock;
setFlags(fl);
if (high != (HighVariable *)0)
high->setSymbol(this);
}