mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
Refactor variable renaming
This commit is contained in:
parent
b88ea8c927
commit
c0dfa509ee
18 changed files with 647 additions and 339 deletions
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue