mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
Merge remote-tracking branch 'origin/GT_3392_DecompilerAPI'
This commit is contained in:
commit
8319b1ba5c
99 changed files with 5477 additions and 2594 deletions
|
@ -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
|
||||
|
@ -2450,33 +2434,73 @@ void ActionNameVars::lookForFuncParamNames(Funcdata &data,const vector<Varnode *
|
|||
}
|
||||
}
|
||||
|
||||
int4 ActionNameVars::apply(Funcdata &data)
|
||||
/// \brief Link symbols associated with a given \e spacebase Varnode
|
||||
///
|
||||
/// Look for PTRSUB ops which indicate a symbol reference within the address space
|
||||
/// referred to by the \e spacebase Varnode. Decode any symbol reference and link it
|
||||
/// to the appropriate HighVariable
|
||||
/// \param vn is the given \e spacebase Varnode
|
||||
/// \param data is the function containing the Varnode
|
||||
/// \param namerec is used to store any recovered Symbol without a name
|
||||
void ActionNameVars::linkSpacebaseSymbol(Varnode *vn,Funcdata &data,vector<Varnode *> &namerec)
|
||||
|
||||
{
|
||||
if (!vn->isConstant() && !vn->isInput()) return;
|
||||
list<PcodeOp *>::const_iterator iter;
|
||||
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
|
||||
PcodeOp *op = *iter;
|
||||
if (op->code() != CPUI_PTRSUB) continue;
|
||||
Varnode *offVn = op->getIn(1);
|
||||
Symbol *sym = data.linkSymbolReference(offVn);
|
||||
if ((sym != (Symbol *)0) && sym->isNameUndefined())
|
||||
namerec.push_back(offVn);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Link formal Symbols to their HighVariable representative in the given Function
|
||||
///
|
||||
/// Run through all HighVariables for the given function and set up the explicit mapping with
|
||||
/// existing Symbol objects. If there is no matching Symbol for a given HighVariable, a new
|
||||
/// Symbol is created. Any Symbol that does not have a name is added to a list for further
|
||||
/// name resolution.
|
||||
/// \param data is the given function
|
||||
/// \param namerec is the container for collecting Symbols with a name
|
||||
void ActionNameVars::linkSymbols(Funcdata &data,vector<Varnode *> &namerec)
|
||||
|
||||
{
|
||||
const AddrSpaceManager *manage = data.getArch();
|
||||
VarnodeLocSet::const_iterator iter,enditer;
|
||||
AddrSpace *spc;
|
||||
vector<Varnode *> namerec; // Name representatives of symbols that need names
|
||||
AddrSpace *constSpace = manage->getConstantSpace();
|
||||
enditer = data.endLoc(constSpace);
|
||||
for(iter=data.beginLoc(constSpace);iter!=enditer;++iter) {
|
||||
Varnode *curvn = *iter;
|
||||
if (curvn->getSymbolEntry() != (SymbolEntry *)0)
|
||||
data.linkSymbol(curvn); // Special equate symbol
|
||||
else if (curvn->isSpacebase())
|
||||
linkSpacebaseSymbol(curvn, data, namerec);
|
||||
}
|
||||
|
||||
for(int4 i=0;i<manage->numSpaces();++i) { // Build a list of nameable highs
|
||||
spc = manage->getSpace(i);
|
||||
if (spc == (AddrSpace *)0) continue;
|
||||
if (spc == constSpace) continue;
|
||||
enditer = data.endLoc(spc);
|
||||
for(iter=data.beginLoc(spc);iter!=enditer;++iter) {
|
||||
Varnode *curvn = *iter;
|
||||
if (curvn->isFree()) {
|
||||
if (curvn->getSymbolEntry() != (SymbolEntry *)0)
|
||||
data.linkSymbol(curvn); // Special equate symbol
|
||||
continue;
|
||||
}
|
||||
if (curvn->isSpacebase())
|
||||
linkSpacebaseSymbol(curvn, data, namerec);
|
||||
Varnode *vn = curvn->getHigh()->getNameRepresentative();
|
||||
if (vn != curvn) continue; // Hit each high only once
|
||||
HighVariable *high = vn->getHigh();
|
||||
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());
|
||||
|
@ -2484,34 +2508,29 @@ int4 ActionNameVars::apply(Funcdata &data)
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lookForRecommendedNames(data); // Make sure recommended names hit before subfunc
|
||||
int4 ActionNameVars::apply(Funcdata &data)
|
||||
|
||||
{
|
||||
vector<Varnode *> namerec;
|
||||
|
||||
linkSymbols(data, namerec);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -3852,67 +3871,15 @@ 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;
|
||||
}
|
||||
|
@ -4893,8 +4860,10 @@ void universal_action(Architecture *conf)
|
|||
act->addAction( new ActionMergeRequired("merge") );
|
||||
act->addAction( new ActionMarkExplicit("merge") );
|
||||
act->addAction( new ActionMarkImplied("merge") ); // This must come BEFORE general merging
|
||||
act->addAction( new ActionMergeMultiEntry("merge") );
|
||||
act->addAction( new ActionMergeCopy("merge") );
|
||||
act->addAction( new ActionDominantCopy("merge") );
|
||||
act->addAction( new ActionDynamicSymbols("dynamic") );
|
||||
act->addAction( new ActionMarkIndirectOnly("merge") ); // Must come after required merges but before speculative
|
||||
act->addAction( new ActionMergeAdjacent("merge") );
|
||||
act->addAction( new ActionMergeType("merge") );
|
||||
|
|
|
@ -380,6 +380,17 @@ public:
|
|||
virtual int4 apply(Funcdata &data) { data.getMerge().mergeOpcode(CPUI_COPY); return 0; }
|
||||
};
|
||||
|
||||
/// \brief Try to merge Varnodes specified by Symbols with multiple SymbolEntrys
|
||||
class ActionMergeMultiEntry : public Action {
|
||||
public:
|
||||
ActionMergeMultiEntry(const string &g) : Action(rule_onceperfunc,"mergemultientry",g) {} ///< Constructor
|
||||
virtual Action *clone(const ActionGroupList &grouplist) const {
|
||||
if (!grouplist.contains(getGroup())) return (Action *)0;
|
||||
return new ActionMergeMultiEntry(getGroup());
|
||||
}
|
||||
virtual int4 apply(Funcdata &data) { data.getMerge().mergeMultiEntry(); return 0; }
|
||||
};
|
||||
|
||||
/// \brief Try to merge Varnodes of the same type (if they don't hold different values at the same time)
|
||||
class ActionMergeType : public Action {
|
||||
public:
|
||||
|
@ -452,8 +463,9 @@ 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);
|
||||
public:
|
||||
ActionNameVars(const string &g) : Action(rule_onceperfunc,"namevars",g) {} ///< Constructor
|
||||
virtual Action *clone(const ActionGroupList &grouplist) const {
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include "funcdata.hh"
|
||||
#include <ctype.h>
|
||||
|
||||
uint8 Symbol::ID_BASE = 0x4000000000000000L;
|
||||
|
||||
/// This SymbolEntry is unintegrated. An address or hash must be provided
|
||||
/// either directly or via restoreXml().
|
||||
/// \param sym is the Symbol \b this will be a map for
|
||||
|
@ -230,6 +232,21 @@ bool Symbol::isNameUndefined(void) const
|
|||
return ((name.size()==15)&&(0==name.compare(0,7,"$$undef")));
|
||||
}
|
||||
|
||||
/// If the given value is \b true, any Varnodes that map directly to \b this Symbol,
|
||||
/// will not be speculatively merged with other Varnodes. (Required merges will still happen).
|
||||
/// \param val is the given boolean value
|
||||
void Symbol::setIsolated(bool val)
|
||||
|
||||
{
|
||||
if (val) {
|
||||
dispflags |= isolate;
|
||||
flags |= Varnode::typelock; // Isolated Symbol must be typelocked
|
||||
checkSizeTypeLock();
|
||||
}
|
||||
else
|
||||
dispflags &= ~((uint4)isolate);
|
||||
}
|
||||
|
||||
/// \return the first SymbolEntry
|
||||
SymbolEntry *Symbol::getFirstWholeMap(void) const
|
||||
|
||||
|
@ -260,6 +277,57 @@ SymbolEntry *Symbol::getMapEntry(const Address &addr) const
|
|||
return (SymbolEntry *)0;
|
||||
}
|
||||
|
||||
/// Among all the SymbolEntrys that map \b this entire Symbol, calculate
|
||||
/// the position of the given SymbolEntry within the list.
|
||||
/// \param entry is the given SymbolEntry
|
||||
/// \return its position within the list or -1 if it is not in the list
|
||||
int4 Symbol::getMapEntryPosition(const SymbolEntry *entry) const
|
||||
|
||||
{
|
||||
int4 pos = 0;
|
||||
for(int4 i=0;i<mapentry.size();++i) {
|
||||
const SymbolEntry *tmp = &(*mapentry[i]);
|
||||
if (tmp == entry)
|
||||
return pos;
|
||||
if (entry->getSize() == type->getSize())
|
||||
pos += 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// A value of 0 means the base Symbol name is visible and not overridden in the given use scope.
|
||||
/// A value of 1 means the base name may be overridden, but the parent scope name is not.
|
||||
/// The minimual number of names that distinguishes \b this Symbol uniquely within the
|
||||
/// use scope is returned.
|
||||
/// \param useScope is the given scope where \b this Symbol is being used
|
||||
/// \return the number of (extra) names needed to distinguish \b this Symbol
|
||||
int4 Symbol::getResolutionDepth(const Scope *useScope) const
|
||||
|
||||
{
|
||||
if (scope == useScope) return 0; // Symbol is in scope where it is used
|
||||
const Scope *distinguishScope = scope->findDistinguishingScope(useScope);
|
||||
int4 depth = 0;
|
||||
string distinguishName;
|
||||
const Scope *terminatingScope;
|
||||
if (distinguishScope == (const Scope *)0) { // Symbol scope is ancestor of use scope
|
||||
distinguishName = name;
|
||||
terminatingScope = scope;
|
||||
}
|
||||
else {
|
||||
distinguishName = distinguishScope->getName();
|
||||
const Scope *currentScope = scope;
|
||||
while(currentScope != distinguishScope) { // For any scope up to the distinguishing scope
|
||||
depth += 1; // Print its name
|
||||
currentScope = currentScope->getParent();
|
||||
}
|
||||
depth += 1; // Also print the distinguishing scope name
|
||||
terminatingScope = distinguishScope->getParent();
|
||||
}
|
||||
if (useScope->isNameUsed(distinguishName,terminatingScope))
|
||||
depth += 1; // Name was overridden, we need one more distinguishing name
|
||||
return depth;
|
||||
}
|
||||
|
||||
/// \param s is the output stream
|
||||
void Symbol::saveXmlHeader(ostream &s) const
|
||||
|
||||
|
@ -278,18 +346,20 @@ void Symbol::saveXmlHeader(ostream &s) const
|
|||
a_v_b(s,"indirectstorage",true);
|
||||
if ((flags&Varnode::hiddenretparm)!=0)
|
||||
a_v_b(s,"hiddenretparm",true);
|
||||
if ((dispflags&isolate)!=0)
|
||||
a_v_b(s,"merge",false);
|
||||
int4 format = getDisplayFormat();
|
||||
if (format != 0) {
|
||||
s << " format=\"";
|
||||
if (format == Symbol::force_hex)
|
||||
if (format == force_hex)
|
||||
s << "hex\"";
|
||||
else if (format == Symbol::force_dec)
|
||||
else if (format == force_dec)
|
||||
s << "dec\"";
|
||||
else if (format == Symbol::force_char)
|
||||
else if (format == force_char)
|
||||
s << "char\"";
|
||||
else if (format == Symbol::force_oct)
|
||||
else if (format == force_oct)
|
||||
s << "oct\"";
|
||||
else if (format == Symbol::force_bin)
|
||||
else if (format == force_bin)
|
||||
s << "bin\"";
|
||||
else
|
||||
s << "hex\"";
|
||||
|
@ -305,50 +375,87 @@ void Symbol::restoreXmlHeader(const Element *el)
|
|||
{
|
||||
name.clear();
|
||||
category = -1;
|
||||
symbolId = 0;
|
||||
for(int4 i=0;i<el->getNumAttributes();++i) {
|
||||
if (el->getAttributeName(i)=="name")
|
||||
name = el->getAttributeValue(i);
|
||||
else if (el->getAttributeName(i)=="cat") {
|
||||
istringstream s(el->getAttributeValue("cat"));
|
||||
s.unsetf(ios::dec | ios::hex | ios::oct);
|
||||
s >> category;
|
||||
}
|
||||
else if (el->getAttributeName(i)=="namelock") {
|
||||
if (xml_readbool(el->getAttributeValue(i)))
|
||||
flags |= Varnode::namelock;
|
||||
}
|
||||
else if (el->getAttributeName(i)=="typelock") {
|
||||
if (xml_readbool(el->getAttributeValue(i)))
|
||||
flags |= Varnode::typelock;
|
||||
}
|
||||
else if (el->getAttributeName(i)=="readonly") {
|
||||
if (xml_readbool(el->getAttributeValue(i)))
|
||||
flags |= Varnode::readonly;
|
||||
}
|
||||
else if (el->getAttributeName(i)=="volatile") {
|
||||
if (xml_readbool(el->getAttributeValue(i)))
|
||||
flags |= Varnode::volatil;
|
||||
}
|
||||
else if (el->getAttributeName(i)=="indirectstorage") {
|
||||
if (xml_readbool(el->getAttributeValue(i)))
|
||||
flags |= Varnode::indirectstorage;
|
||||
}
|
||||
else if (el->getAttributeName(i)=="hiddenretparm") {
|
||||
if (xml_readbool(el->getAttributeValue(i)))
|
||||
flags |= Varnode::hiddenretparm;
|
||||
}
|
||||
else if (el->getAttributeName(i)=="format") {
|
||||
const string &formString( el->getAttributeValue(i));
|
||||
if (formString == "hex")
|
||||
dispflags |= Symbol::force_hex;
|
||||
else if (formString == "dec")
|
||||
dispflags |= Symbol::force_dec;
|
||||
else if (formString == "char")
|
||||
dispflags |= Symbol::force_char;
|
||||
else if (formString == "oct")
|
||||
dispflags |= Symbol::force_oct;
|
||||
else if (formString == "bin")
|
||||
dispflags |= Symbol::force_bin;
|
||||
const string &attName(el->getAttributeName(i));
|
||||
switch (attName[0]) {
|
||||
case 'c':
|
||||
if (attName == "cat") {
|
||||
istringstream s(el->getAttributeValue(i));
|
||||
s.unsetf(ios::dec | ios::hex | ios::oct);
|
||||
s >> category;
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
if (attName == "format") {
|
||||
const string &formString(el->getAttributeValue(i));
|
||||
if (formString == "hex")
|
||||
dispflags |= force_hex;
|
||||
else if (formString == "dec")
|
||||
dispflags |= force_dec;
|
||||
else if (formString == "char")
|
||||
dispflags |= force_char;
|
||||
else if (formString == "oct")
|
||||
dispflags |= force_oct;
|
||||
else if (formString == "bin")
|
||||
dispflags |= force_bin;
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
if (attName == "hiddenretparm") {
|
||||
if (xml_readbool(el->getAttributeValue(i)))
|
||||
flags |= Varnode::hiddenretparm;
|
||||
}
|
||||
break;
|
||||
case 'i':
|
||||
if (attName == "id") {
|
||||
istringstream s(el->getAttributeValue(i));
|
||||
s.unsetf(ios::dec | ios::hex | ios::oct);
|
||||
s >> symbolId;
|
||||
if ((symbolId >> 56) == (ID_BASE >> 56))
|
||||
symbolId = 0; // Don't keep old internal id's
|
||||
}
|
||||
else if (attName == "indirectstorage") {
|
||||
if (xml_readbool(el->getAttributeValue(i)))
|
||||
flags |= Varnode::indirectstorage;
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
if (attName == "merge") {
|
||||
if (!xml_readbool(el->getAttributeValue(i))) {
|
||||
dispflags |= isolate;
|
||||
flags |= Varnode::typelock;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
if (attName == "name")
|
||||
name = el->getAttributeValue(i);
|
||||
else if (attName == "namelock") {
|
||||
if (xml_readbool(el->getAttributeValue(i)))
|
||||
flags |= Varnode::namelock;
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
if (attName == "readonly") {
|
||||
if (xml_readbool(el->getAttributeValue(i)))
|
||||
flags |= Varnode::readonly;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
if (attName == "typelock") {
|
||||
if (xml_readbool(el->getAttributeValue(i)))
|
||||
flags |= Varnode::typelock;
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
if (attName == "volatile") {
|
||||
if (xml_readbool(el->getAttributeValue(i)))
|
||||
flags |= Varnode::volatil;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (category == 0) {
|
||||
|
@ -465,10 +572,12 @@ void FunctionSymbol::saveXml(ostream &s) const
|
|||
|
||||
{
|
||||
if (fd != (Funcdata *)0)
|
||||
fd->saveXml(s,false); // Save the function itself
|
||||
fd->saveXml(s,symbolId,false); // Save the function itself
|
||||
else {
|
||||
s << "<functionshell";
|
||||
a_v(s,"name",name);
|
||||
if (symbolId != 0)
|
||||
a_v_u(s,"id",symbolId);
|
||||
s << "/>\n";
|
||||
}
|
||||
}
|
||||
|
@ -478,7 +587,7 @@ void FunctionSymbol::restoreXml(const Element *el)
|
|||
{
|
||||
if (el->getName() == "function") {
|
||||
fd = new Funcdata("",scope,Address());
|
||||
fd->restoreXml(el);
|
||||
symbolId = fd->restoreXml(el);
|
||||
name = fd->getName();
|
||||
if (consumeSize < fd->getSize()) {
|
||||
if ((fd->getSize()>1)&&(fd->getSize() <= 8))
|
||||
|
@ -486,7 +595,17 @@ void FunctionSymbol::restoreXml(const Element *el)
|
|||
}
|
||||
}
|
||||
else { // functionshell
|
||||
name = el->getAttributeValue("name");
|
||||
symbolId = 0;
|
||||
for(int4 i=0;i<el->getNumAttributes();++i) {
|
||||
const string &attrName(el->getAttributeName(i));
|
||||
if (attrName == "name")
|
||||
name = el->getAttributeValue(i);
|
||||
else if (attrName == "id") {
|
||||
istringstream s(el->getAttributeValue(i));
|
||||
s.unsetf(ios::dec | ios::hex | ios::oct);
|
||||
s >> symbolId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -683,7 +802,7 @@ void Scope::attachScope(Scope *child)
|
|||
|
||||
{
|
||||
child->parent = this;
|
||||
pair<const ScopeKey,Scope *> value(ScopeKey(child->name,child->dedupId),child);
|
||||
pair<const ScopeKey,Scope *> value(ScopeKey(child->name,child->uniqueId),child);
|
||||
pair<ScopeMap::iterator,bool> res;
|
||||
if (child->name.size()==0)
|
||||
throw LowlevelError("Non-global scope has empty name");
|
||||
|
@ -1257,6 +1376,74 @@ void Scope::getNameSegments(vector<string> &vec) const
|
|||
}
|
||||
}
|
||||
|
||||
/// Put the parent scopes of \b this into an array in order, starting with the global scope.
|
||||
/// This scope itself will not be in the array.
|
||||
/// \param vec is storage for the array of scopes
|
||||
void Scope::getScopePath(vector<Scope *> &vec) const
|
||||
|
||||
{
|
||||
int4 count = 0;
|
||||
Scope *cur = parent;
|
||||
while(cur != (Scope *)0) { // Count number of elements in path
|
||||
count += 1;
|
||||
cur = cur->parent;
|
||||
}
|
||||
vec.resize(count);
|
||||
cur = parent;
|
||||
while(cur != (Scope *)0) {
|
||||
count -= 1;
|
||||
vec[count] = cur;
|
||||
cur = cur->parent;
|
||||
}
|
||||
}
|
||||
|
||||
/// Test for the presence of a symbol with the given name in either \b this scope or
|
||||
/// an ancestor scope up to but not including the given terminating scope.
|
||||
/// If the name is used \b true is returned.
|
||||
/// \param nm is the given name to test
|
||||
/// \param op2 is the terminating ancestor scope (or null)
|
||||
bool Scope::isNameUsed(const string &nm,const Scope *op2) const
|
||||
|
||||
{
|
||||
const Scope *currentScope = this;
|
||||
while(currentScope != op2) {
|
||||
if (currentScope->isNameUsed(name))
|
||||
return true;
|
||||
currentScope = currentScope->parent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Any two scopes share at least the \e global scope as a common ancestor. We find the first scope
|
||||
/// that is \e not in common. The scope returned will always be an ancestor of \b this.
|
||||
/// If \b this is an ancestor of the other given scope, then null is returned.
|
||||
/// \param op2 is the other given Scope
|
||||
/// \return the first ancestor Scope that is not in common or null
|
||||
const Scope *Scope::findDistinguishingScope(const Scope *op2) const
|
||||
|
||||
{
|
||||
if (this == op2) return (Scope *)0; // Quickly check most common cases
|
||||
if (parent == op2) return this;
|
||||
if (op2->parent == this) return op2;
|
||||
if (parent == op2->parent) return this;
|
||||
vector<Scope *> thisPath;
|
||||
vector<Scope *> op2Path;
|
||||
getScopePath(thisPath);
|
||||
op2->getScopePath(op2Path);
|
||||
int4 min = thisPath.size();
|
||||
if (op2Path.size() < min)
|
||||
min = op2Path.size();
|
||||
for(int4 i=0;i<min;++i) {
|
||||
if (thisPath[i] != op2Path[i])
|
||||
return thisPath[i];
|
||||
}
|
||||
if (min < thisPath.size())
|
||||
return thisPath[min]; // thisPath matches op2Path but is longer
|
||||
if (min < op2Path.size())
|
||||
return (Scope *)0; // op2Path matches thisPath but is longer
|
||||
return this; // ancestor paths are identical (only base scopes differ)
|
||||
}
|
||||
|
||||
/// The Symbol is created and added to any name map, but no SymbolEntry objects are created for it.
|
||||
/// \param name is the name of the new Symbol
|
||||
/// \param ct is a data-type to assign to the new Symbol
|
||||
|
@ -1454,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,
|
||||
|
@ -1473,6 +1699,10 @@ bool Scope::isReadOnly(const Address &addr,int4 size,const Address &usepoint) co
|
|||
void ScopeInternal::addSymbolInternal(Symbol *sym)
|
||||
|
||||
{
|
||||
if (sym->symbolId == 0) {
|
||||
sym->symbolId = Symbol::ID_BASE + (((uint8)uniqueId & 0xffff) << 40) + nextUniqueId;
|
||||
nextUniqueId += 1;
|
||||
}
|
||||
try {
|
||||
if (sym->name.size() == 0)
|
||||
sym->name = buildUndefinedName();
|
||||
|
@ -1520,6 +1750,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 (sz == sym->type->getSize()) {
|
||||
sym->wholeCount += 1;
|
||||
if (sym->wholeCount == 2)
|
||||
multiEntrySet.insert(sym);
|
||||
}
|
||||
return &(*iter);
|
||||
}
|
||||
|
||||
|
@ -1530,6 +1765,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 (sz == sym->type->getSize()) {
|
||||
sym->wholeCount += 1;
|
||||
if (sym->wholeCount == 2)
|
||||
multiEntrySet.insert(sym);
|
||||
}
|
||||
return &dynamicentry.back();
|
||||
}
|
||||
|
||||
|
@ -1594,6 +1834,7 @@ list<SymbolEntry>::iterator ScopeInternal::endDynamic(void)
|
|||
ScopeInternal::ScopeInternal(const string &nm,Architecture *g)
|
||||
: Scope(nm,g)
|
||||
{
|
||||
nextUniqueId = 0;
|
||||
int4 numspaces = g->numSpaces();
|
||||
for(int4 i=0;i<numspaces;++i)
|
||||
maptable.push_back((EntryMap *)0);
|
||||
|
@ -1624,6 +1865,7 @@ void ScopeInternal::clear(void)
|
|||
Symbol *sym = *iter++;
|
||||
removeSymbol(sym);
|
||||
}
|
||||
nextUniqueId = 0;
|
||||
}
|
||||
|
||||
/// Look for NULL entries in the category tables. If there are,
|
||||
|
@ -1740,18 +1982,13 @@ 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
|
||||
for(iter=symbol->mapentry.begin();iter!=symbol->mapentry.end();++iter) {
|
||||
AddrSpace *spc = (*(*iter)).getAddr().getSpace();
|
||||
|
@ -1762,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;
|
||||
}
|
||||
|
@ -1769,10 +2020,14 @@ void ScopeInternal::removeSymbol(Symbol *symbol)
|
|||
void ScopeInternal::renameSymbol(Symbol *sym,const string &newname)
|
||||
|
||||
{
|
||||
nametree.erase(sym); // Erase under old name
|
||||
nametree.erase(sym); // Erase under old name
|
||||
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->wholeCount > 1)
|
||||
multiEntrySet.insert(sym); // Reenter into the multi-entry set now that name is changed
|
||||
}
|
||||
|
||||
void ScopeInternal::retypeSymbol(Symbol *sym,Datatype *ct)
|
||||
|
@ -1795,6 +2050,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;
|
||||
|
@ -2021,6 +2277,15 @@ void ScopeInternal::findByName(const string &name,vector<Symbol *> &res) const
|
|||
}
|
||||
}
|
||||
|
||||
bool ScopeInternal::isNameUsed(const string &name) const
|
||||
|
||||
{
|
||||
Symbol sym((Scope *)0,name,(Datatype *)0);
|
||||
SymbolNameTree::const_iterator iter = nametree.lower_bound(&sym);
|
||||
if (iter == nametree.end()) return false;
|
||||
return ((*iter)->getName() == name);
|
||||
}
|
||||
|
||||
string ScopeInternal::buildVariableName(const Address &addr,
|
||||
const Address &pc,
|
||||
Datatype *ct,int4 &index,uint4 flags) const
|
||||
|
@ -2435,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
|
||||
|
@ -2509,9 +2794,12 @@ void Database::attachScope(Scope *newscope,Scope *parent)
|
|||
throw LowlevelError("Multiple global scopes");
|
||||
if (newscope->name.size() != 0)
|
||||
throw LowlevelError("Global scope does not have empty name");
|
||||
newscope->assignId(0);
|
||||
globalscope = newscope;
|
||||
return;
|
||||
}
|
||||
newscope->assignId(nextScopeId);
|
||||
nextScopeId += 1;
|
||||
parent->attachScope(newscope);
|
||||
}
|
||||
|
||||
|
@ -2525,7 +2813,7 @@ void Database::deleteScope(Scope *scope)
|
|||
delete scope;
|
||||
}
|
||||
else {
|
||||
ScopeKey key(scope->name,scope->dedupId);
|
||||
ScopeKey key(scope->name,scope->uniqueId);
|
||||
ScopeMap::iterator iter = scope->parent->children.find(key);
|
||||
if (iter == scope->parent->children.end())
|
||||
throw LowlevelError("Could not remove parent reference to: "+scope->name);
|
||||
|
|
|
@ -157,15 +157,17 @@ class Symbol {
|
|||
protected:
|
||||
Scope *scope; ///< The scope that owns this symbol
|
||||
string name; ///< The local name of the symbol
|
||||
uint4 nameDedup; ///< id to distinguish symbols with the same name
|
||||
Datatype *type; ///< The symbol's data-type
|
||||
uint4 nameDedup; ///< id to distinguish symbols with the same name
|
||||
uint4 flags; ///< Varnode-like properties of the symbol
|
||||
// only typelock,namelock,readonly,externref
|
||||
// addrtied, persist inherited from scope
|
||||
uint4 dispflags; ///< Flags affecting the display of this symbol
|
||||
int2 category; ///< Special category (-1==none 0=parameter 1=equate)
|
||||
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 checkSizeTypeLock(void); ///< Calculate if \b size_typelock property is on
|
||||
|
@ -177,18 +179,20 @@ public:
|
|||
force_oct = 3, ///< Force octal printing of constant symbol
|
||||
force_bin = 4, ///< Force binary printing of constant symbol
|
||||
force_char = 5, ///< Force integer to be printed as a character constant
|
||||
size_typelock = 8 ///< Only the size of the symbol is typelocked
|
||||
size_typelock = 8, ///< Only the size of the symbol is typelocked
|
||||
isolate = 16, ///< Symbol should not speculatively merge automatically
|
||||
merge_problems = 32 ///< Set if some SymbolEntrys did not get merged
|
||||
};
|
||||
/// \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; }
|
||||
{ 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; }
|
||||
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
|
||||
uint4 getId(void) const { return (uint4)(uintp)this; } ///< Get a unique id for the symbol
|
||||
uint8 getId(void) const { return symbolId; } ///< Get a unique id for the symbol
|
||||
uint4 getFlags(void) const { return flags; } ///< Get the boolean properties of the Symbol
|
||||
uint4 getDisplayFormat(void) const { return (dispflags & 7); } ///< Get the format to display the Symbol in
|
||||
int2 getCategory(void) const { return category; } ///< Get the Symbol category
|
||||
|
@ -199,9 +203,18 @@ public:
|
|||
bool isIndirectStorage(void) const { return ((flags&Varnode::indirectstorage)!=0); } ///< Is storage really a pointer to the true Symbol
|
||||
bool isHiddenReturn(void) const { return ((flags&Varnode::hiddenretparm)!=0); } ///< Is this a reference to the function return value
|
||||
bool isNameUndefined(void) const; ///< Does \b this have an undefined name
|
||||
bool isMultiEntry(void) const { return (wholeCount > 1); } ///< Does \b this have more than one \e entire mapping
|
||||
bool hasMergeProblems(void) const { return ((dispflags & merge_problems)!=0); } ///< Were some SymbolEntrys not merged
|
||||
void setMergeProblems(void) { dispflags |= merge_problems; } ///< Mark that some SymbolEntrys could not be merged
|
||||
bool isIsolated(void) const { return ((dispflags & isolate)!=0); } ///< Return \b true if \b this is isolated from speculative merging
|
||||
void setIsolated(bool val); ///< Set whether \b this Symbol should be speculatively merged
|
||||
Scope *getScope(void) const { return scope; } ///< Get the scope owning \b this Symbol
|
||||
SymbolEntry *getFirstWholeMap(void) const; ///< Get the first entire mapping of the symbol
|
||||
SymbolEntry *getMapEntry(const Address &addr) const; ///< Get first mapping of the symbol that contains the given Address
|
||||
int4 numEntries(void) const { return mapentry.size(); } ///< Return the number of SymbolEntrys
|
||||
SymbolEntry *getMapEntry(int4 i) const { return &(*mapentry[i]); } ///< Return the i-th SymbolEntry for \b this Symbol
|
||||
int4 getMapEntryPosition(const SymbolEntry *entry) const; ///< Position of given SymbolEntry within \b this multi-entry Symbol
|
||||
int4 getResolutionDepth(const Scope *useScope) const; ///< Get the number of scope names to print to resolve symbol in given context
|
||||
void saveXmlHeader(ostream &s) const; ///< Save basic Symbol properties as XML attributes
|
||||
void restoreXmlHeader(const Element *el); ///< Restore basic Symbol properties from XML
|
||||
void saveXmlBody(ostream &s) const; ///< Save details of the Symbol to XML
|
||||
|
@ -209,6 +222,7 @@ public:
|
|||
virtual void saveXml(ostream &s) const; ///< Save \b this Symbol to an XML stream
|
||||
virtual void restoreXml(const Element *el); ///< Restore \b this Symbol from an XML stream
|
||||
virtual int4 getBytesConsumed(void) const; ///< Get number of bytes consumed within the address->symbol map
|
||||
static uint8 ID_BASE; ///< Base of internal ID's
|
||||
};
|
||||
|
||||
/// Force a specific display format for constant symbols
|
||||
|
@ -404,12 +418,13 @@ class Scope {
|
|||
ScopeMap children; ///< Sorted list of child scopes
|
||||
void attachScope(Scope *child); ///< Attach a new child Scope to \b this
|
||||
void detachScope(ScopeMap::iterator iter); ///< Detach a child Scope from \b this
|
||||
void assignId(uint4 val) { uniqueId = val; } ///< Let the database assign a unique id to \b this scope
|
||||
|
||||
protected:
|
||||
Architecture *glb; ///< Architecture of \b this scope
|
||||
string name; ///< Name of \b this scope
|
||||
Funcdata *fd; ///< (If non-null) the function which \b this is the local Scope for
|
||||
uint4 dedupId; ///< Id to dedup scopes with same name (when allowed)
|
||||
uint4 uniqueId; ///< Unique id for the scope, for deduping scope names, assigning symbol ids
|
||||
static const Scope *stackAddr(const Scope *scope1,
|
||||
const Scope *scope2,
|
||||
const Address &addr,
|
||||
|
@ -479,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;
|
||||
|
@ -487,7 +503,7 @@ public:
|
|||
#endif
|
||||
/// \brief Construct an empty scope, given a name and Architecture
|
||||
Scope(const string &nm,Architecture *g) {
|
||||
name = nm; glb = g; parent = (Scope *)0; fd = (Funcdata *)0; dedupId = 0;
|
||||
name = nm; glb = g; parent = (Scope *)0; fd = (Funcdata *)0; uniqueId = 0;
|
||||
#ifdef OPACTION_DEBUG
|
||||
debugon = false;
|
||||
#endif
|
||||
|
@ -515,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
|
||||
|
||||
|
@ -587,6 +604,14 @@ public:
|
|||
/// \param res will contain any matching Symbols
|
||||
virtual void findByName(const string &name,vector<Symbol *> &res) const=0;
|
||||
|
||||
/// \brief Check if the given name is used within \b this scope.
|
||||
///
|
||||
/// Only \b this scope is checked. If one or more symbols exist with the given name,
|
||||
/// \b true is returned.
|
||||
/// \param name is the given name to check for
|
||||
/// \return \b true if the name is used within \b this scope
|
||||
virtual bool isNameUsed(const string &name) const=0;
|
||||
|
||||
/// \brief Convert an \e external \e reference to the referenced function
|
||||
///
|
||||
/// \param sym is the Symbol marking the external reference
|
||||
|
@ -669,6 +694,9 @@ public:
|
|||
bool isSubScope(const Scope *scp) const; ///< Is this a sub-scope of the given Scope
|
||||
string getFullName(void) const; ///< Get the full name of \b this Scope
|
||||
void getNameSegments(vector<string> &vec) const; ///< Get the fullname of \b this in segments
|
||||
void getScopePath(vector<Scope *> &vec) const; ///< Get the ordered list of parent scopes to \b this
|
||||
bool isNameUsed(const string &nm,const Scope *op2) const; ///< Is the given name in use within given scope path
|
||||
const Scope *findDistinguishingScope(const Scope *op2) const; ///< Find first ancestor of \b this not shared by given scope
|
||||
Architecture *getArch(void) const { return glb; } ///< Get the Architecture associated with \b this
|
||||
Scope *getParent(void) const { return parent; } ///< Get the parent Scope (or NULL if \b this is the global Scope)
|
||||
Symbol *addSymbol(const string &name,Datatype *ct); ///< Add a new Symbol \e without mapping it to an address
|
||||
|
@ -679,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
|
||||
};
|
||||
|
@ -702,6 +731,8 @@ protected:
|
|||
vector<EntryMap *> maptable; ///< Rangemaps of SymbolEntry, one map for each address space
|
||||
vector<vector<Symbol *> > category; ///< References to Symbol objects organized by category
|
||||
list<SymbolEntry> dynamicentry; ///< Dynamic symbol entries
|
||||
SymbolNameTree multiEntrySet; ///< Set of symbols with multiple entries
|
||||
uint8 nextUniqueId; ///< Next available symbol id
|
||||
public:
|
||||
ScopeInternal(const string &nm,Architecture *g); ///< Construct the Scope
|
||||
virtual void clear(void);
|
||||
|
@ -716,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);
|
||||
|
@ -734,6 +766,7 @@ public:
|
|||
virtual SymbolEntry *findOverlap(const Address &addr,int4 size) const;
|
||||
|
||||
virtual void findByName(const string &name,vector<Symbol *> &res) const;
|
||||
virtual bool isNameUsed(const string &name) const;
|
||||
virtual Funcdata *resolveExternalRefFunction(ExternRefSymbol *sym) const;
|
||||
|
||||
virtual string buildVariableName(const Address &addr,
|
||||
|
@ -747,6 +780,9 @@ 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
|
||||
static void restorePathXml(vector<string> &vec,const Element *el); ///< Restore path from \<val> tags
|
||||
};
|
||||
|
@ -804,12 +840,13 @@ class Database {
|
|||
Scope *globalscope; ///< A quick reference to the \e global Scope
|
||||
ScopeResolve resolvemap; ///< The Address to \e namespace map
|
||||
partmap<Address,uint4> flagbase; ///< Map of global properties
|
||||
uint4 nextScopeId; ///< Id for next attached scope (0 reserved for global scope)
|
||||
void clearResolve(Scope *scope); ///< Clear the \e ownership ranges associated with the given Scope
|
||||
void clearResolveRecursive(Scope *scope); ///< Clear the \e ownership ranges of a given Scope and its children
|
||||
void fillResolve(Scope *scope); ///< Add the \e ownership ranges of the given Scope to the map
|
||||
static void parseParentTag(const Element *el,string &name,vector<string> &parnames);
|
||||
public:
|
||||
Database(Architecture *g) { glb=g; globalscope=(Scope *)0; flagbase.defaultValue() = 0; } ///< Constructor
|
||||
Database(Architecture *g) { glb=g; globalscope=(Scope *)0; flagbase.defaultValue()=0; nextScopeId=1; } ///< Constructor
|
||||
~Database(void); ///< Destructor
|
||||
Architecture *getArch(void) const { return glb; } ///< Get the Architecture associate with \b this
|
||||
void attachScope(Scope *newscope,Scope *parent); ///< Register a new Scope
|
||||
|
|
|
@ -89,6 +89,7 @@ public:
|
|||
|
||||
virtual SymbolEntry *findOverlap(const Address &addr,int4 size) const { throw LowlevelError("findOverlap unimplemented"); }
|
||||
virtual void findByName(const string &name,vector<Symbol *> &res) const { throw LowlevelError("findByName unimplemented"); }
|
||||
virtual bool isNameUsed(const string &name) const { throw LowlevelError("isNameUsed unimplemented"); }
|
||||
|
||||
virtual MapIterator begin(void) const { throw LowlevelError("begin unimplemented"); }
|
||||
virtual MapIterator end(void) const { throw LowlevelError("end unimplemented"); }
|
||||
|
@ -100,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"); }
|
||||
|
|
|
@ -393,7 +393,7 @@ void DynamicHash::uniqueHash(const Varnode *root,Funcdata *fd)
|
|||
/// \param addr is the given address
|
||||
/// \param h is the hash
|
||||
/// \return the matching Varnode or NULL
|
||||
Varnode *DynamicHash::findVarnode(Funcdata *fd,const Address &addr,uint8 h)
|
||||
Varnode *DynamicHash::findVarnode(const Funcdata *fd,const Address &addr,uint8 h)
|
||||
|
||||
{
|
||||
uint4 method = getMethodFromHash(h);
|
||||
|
@ -423,7 +423,7 @@ Varnode *DynamicHash::findVarnode(Funcdata *fd,const Address &addr,uint8 h)
|
|||
/// \param fd is the function holding the data-flow
|
||||
/// \param addr is the given address
|
||||
/// \param h is the given hash
|
||||
void DynamicHash::gatherFirstLevelVars(vector<Varnode *> &varlist,Funcdata *fd,const Address &addr,uint8 h)
|
||||
void DynamicHash::gatherFirstLevelVars(vector<Varnode *> &varlist,const Funcdata *fd,const Address &addr,uint8 h)
|
||||
|
||||
{
|
||||
OpCode opc = getOpCodeFromHash(h);
|
||||
|
|
|
@ -79,11 +79,11 @@ public:
|
|||
void clear(void); ///< Called for each additional hash (after the first)
|
||||
void calcHash(const Varnode *root,uint4 method); ///< Calculate the hash for given Varnode and method
|
||||
void uniqueHash(const Varnode *root,Funcdata *fd); ///< Select a unique hash for the given Varnode
|
||||
Varnode *findVarnode(Funcdata *fd,const Address &addr,uint8 h);
|
||||
Varnode *findVarnode(const Funcdata *fd,const Address &addr,uint8 h);
|
||||
uint8 getHash(void) const { return hash; } ///< Get the (current) hash
|
||||
|
||||
const Address &getAddress(void) const { return addrresult; } ///< Get the (current) address
|
||||
static void gatherFirstLevelVars(vector<Varnode *> &varlist,Funcdata *fd,const Address &addr,uint8 h);
|
||||
static void gatherFirstLevelVars(vector<Varnode *> &varlist,const Funcdata *fd,const Address &addr,uint8 h);
|
||||
static int4 getSlotFromHash(uint8 h); ///< Retrieve the encoded slot from a hash
|
||||
static uint4 getMethodFromHash(uint8 h); ///< Retrieve the encoded method from a hash
|
||||
static OpCode getOpCodeFromHash(uint8 h); ///< Retrieve the encoded op-code from a hash
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -607,7 +607,6 @@ void Funcdata::saveVarnodeXml(ostream &s,VarnodeLocSet::const_iterator iter,Varn
|
|||
void Funcdata::saveXmlHigh(ostream &s) const
|
||||
|
||||
{
|
||||
int4 j;
|
||||
Varnode *vn;
|
||||
HighVariable *high;
|
||||
|
||||
|
@ -620,32 +619,7 @@ void Funcdata::saveXmlHigh(ostream &s) const
|
|||
high = vn->getHigh();
|
||||
if (high->isMark()) continue;
|
||||
high->setMark();
|
||||
vn = high->getNameRepresentative(); // Get representative varnode
|
||||
s << "<high ";
|
||||
// a_v(s,"name",high->getName());
|
||||
a_v_u(s,"repref",vn->getCreateIndex());
|
||||
if (high->isSpacebase()||high->isImplied()) // This is a special variable
|
||||
a_v(s,"class",string("other"));
|
||||
else if (high->isPersist()&&high->isAddrTied()) // Global variable
|
||||
a_v(s,"class",string("global"));
|
||||
else if (high->isConstant())
|
||||
a_v(s,"class",string("constant"));
|
||||
else if (!high->isPersist())
|
||||
a_v(s,"class",string("local"));
|
||||
else
|
||||
a_v(s,"class",string("other"));
|
||||
if (high->isTypeLock())
|
||||
a_v_b(s,"typelock",true);
|
||||
if (high->getSymbol() != (Symbol *)0)
|
||||
a_v_u(s,"symref",high->getSymbol()->getId());
|
||||
s << '>';
|
||||
high->getType()->saveXml(s);
|
||||
for(j=0;j<high->numInstances();++j) {
|
||||
s << "<addr ";
|
||||
a_v_u(s,"ref",high->getInstance(j)->getCreateIndex());
|
||||
s << "/>";
|
||||
}
|
||||
s << "</high>";
|
||||
high->saveXml(s);
|
||||
}
|
||||
for(iter=beginLoc();iter!=endLoc();++iter) {
|
||||
vn = *iter;
|
||||
|
@ -708,11 +682,14 @@ void Funcdata::saveXmlTree(ostream &s) const
|
|||
/// If indicated by the caller, a description of the entire PcodeOp and Varnode
|
||||
/// tree is also emitted.
|
||||
/// \param s is the output stream
|
||||
/// \param id is the unique id associated with the function symbol
|
||||
/// \param savetree is \b true if the p-code tree should be emitted
|
||||
void Funcdata::saveXml(ostream &s,bool savetree) const
|
||||
void Funcdata::saveXml(ostream &s,uint8 id,bool savetree) const
|
||||
|
||||
{
|
||||
s << "<function";
|
||||
if (id != 0)
|
||||
a_v_u(s, "id", id);
|
||||
a_v(s,"name",name);
|
||||
a_v_i(s,"size",size);
|
||||
if (hasNoCode())
|
||||
|
@ -738,22 +715,30 @@ void Funcdata::saveXml(ostream &s,bool savetree) const
|
|||
/// From an XML \<function> tag, recover the name, address, prototype, symbol,
|
||||
/// jump-table, and override information for \b this function.
|
||||
/// \param el is the root \<function> tag
|
||||
void Funcdata::restoreXml(const Element *el)
|
||||
/// \return the symbol id associated with the function
|
||||
uint8 Funcdata::restoreXml(const Element *el)
|
||||
|
||||
{
|
||||
// clear(); // Shouldn't be needed
|
||||
name.clear();
|
||||
size = -1;
|
||||
uint8 id = 0;
|
||||
AddrSpace *stackid = glb->getStackSpace();
|
||||
for(int4 i=0;i<el->getNumAttributes();++i) {
|
||||
if (el->getAttributeName(i) == "name")
|
||||
const string &attrName(el->getAttributeName(i));
|
||||
if (attrName == "name")
|
||||
name = el->getAttributeValue(i);
|
||||
else if (el->getAttributeName(i) == "size") {
|
||||
else if (attrName == "size") {
|
||||
istringstream s( el->getAttributeValue(i));
|
||||
s.unsetf(ios::dec | ios::hex | ios::oct);
|
||||
s >> size;
|
||||
}
|
||||
else if (el->getAttributeName(i) == "nocode") {
|
||||
else if (attrName == "id") {
|
||||
istringstream s( el->getAttributeValue(i));
|
||||
s.unsetf(ios::dec | ios::hex | ios::oct);
|
||||
s >> id;
|
||||
}
|
||||
else if (attrName == "nocode") {
|
||||
if (xml_readbool(el->getAttributeValue(i)))
|
||||
flags |= no_code;
|
||||
}
|
||||
|
@ -805,6 +790,7 @@ void Funcdata::restoreXml(const Element *el)
|
|||
funcp.setScope(localmap,baseaddr+ -1);
|
||||
}
|
||||
localmap->resetLocalWindow();
|
||||
return id;
|
||||
}
|
||||
|
||||
/// \brief Inject p-code from a \e payload into \b this live function
|
||||
|
|
|
@ -171,8 +171,8 @@ public:
|
|||
void printVarnodeTree(ostream &s) const; ///< Print a description of all Varnodes to a stream
|
||||
void printBlockTree(ostream &s) const; ///< Print a description of control-flow structuring to a stream
|
||||
void printLocalRange(ostream &s) const; ///< Print description of memory ranges associated with local scopes
|
||||
void saveXml(ostream &s,bool savetree) const; ///< Emit an XML description of \b this function to stream
|
||||
void restoreXml(const Element *el); ///< Restore the state of \b this function from an XML description
|
||||
void saveXml(ostream &s,uint8 id,bool savetree) const; ///< Emit an XML description of \b this function to stream
|
||||
uint8 restoreXml(const Element *el); ///< Restore the state of \b this function from an XML description
|
||||
void saveXmlJumpTable(ostream &s) const; ///< Emit an XML description of jump-tables to stream
|
||||
void restoreXmlJumpTable(const Element *el); ///< Restore jump-tables from an XML description
|
||||
void saveXmlTree(ostream &s) const; ///< Save an XML description of the p-code tree to stream
|
||||
|
@ -382,9 +382,16 @@ 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);
|
||||
bool attemptDynamicMappingLate(SymbolEntry *entry,DynamicHash &dhash);
|
||||
Merge &getMerge(void) { return covermerge; } ///< Get the Merge object for \b this function
|
||||
|
||||
// op routines
|
||||
|
|
|
@ -525,6 +525,7 @@ Varnode *Funcdata::opStackLoad(AddrSpace *spc,uintb off,uint4 sz,PcodeOp *op,Var
|
|||
/// CPUI_INT_MULT PcodeOp. If finalization is requested and a new PcodeOp is needed, the output
|
||||
/// Varnode is marked as \e implicit and has its data-type set
|
||||
/// \param op is the given PTRADD
|
||||
/// \param finalize is \b true if finalization is needed for any new PcodeOp
|
||||
void Funcdata::opUndoPtradd(PcodeOp *op,bool finalize)
|
||||
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
@ -313,18 +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();
|
||||
|
||||
VarnodeLocSet::const_iterator iter,enditer;
|
||||
HighVariable *high;
|
||||
Varnode *vn = findLinkedVarnode(sym->getFirstWholeMap());
|
||||
if (vn != (Varnode *)0)
|
||||
return vn->getHigh();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -913,7 +899,16 @@ bool Funcdata::syncVarnodesWithSymbol(VarnodeLocSet::const_iterator &iter,uint4
|
|||
vn = *iter++;
|
||||
if (vn->isFree()) continue;
|
||||
vnflags = vn->getFlags();
|
||||
if ((vnflags & mask) != flags) { // We have a change
|
||||
if (vn->mapentry != (SymbolEntry *)0) { // If there is already an attached SymbolEntry (dynamic)
|
||||
uint4 localMask = mask & ~Varnode::mapped; // Make sure 'mapped' bit is unchanged
|
||||
uint4 localFlags = flags & localMask;
|
||||
if ((vnflags & localMask) != localFlags) {
|
||||
updateoccurred = true;
|
||||
vn->setFlags(localFlags);
|
||||
vn->clearFlags((~localFlags)&localMask);
|
||||
}
|
||||
}
|
||||
else if ((vnflags & mask) != flags) { // We have a change
|
||||
updateoccurred = true;
|
||||
vn->setFlags(flags);
|
||||
vn->clearFlags((~flags)&mask);
|
||||
|
@ -927,6 +922,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())
|
||||
|
@ -941,38 +979,117 @@ 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;
|
||||
}
|
||||
|
||||
/// A reference to a symbol (i.e. &varname) is typically stored as a PTRSUB operation, where the
|
||||
/// first input Varnode is a \e spacebase Varnode indicating whether the symbol is on the \e stack or at
|
||||
/// a \e global RAM location. The second input Varnode is a constant encoding the address of the symbol.
|
||||
/// This method takes this constant Varnode, recovers the symbol it is referring to, and stores
|
||||
/// on the HighVariable object attached to the Varnode.
|
||||
/// \param vn is the constant Varnode (second input) to a PTRSUB operation
|
||||
/// \return the symbol being referred to or null
|
||||
Symbol *Funcdata::linkSymbolReference(Varnode *vn)
|
||||
|
||||
{
|
||||
PcodeOp *op = vn->loneDescend();
|
||||
Varnode *in0 = op->getIn(0);
|
||||
TypePointer *ptype = (TypePointer *)in0->getHigh()->getType();
|
||||
if (ptype->getMetatype() != TYPE_PTR) return (Symbol *)0;
|
||||
TypeSpacebase *sb = (TypeSpacebase *)ptype->getPtrTo();
|
||||
if (sb->getMetatype() != TYPE_SPACEBASE)
|
||||
return (Symbol *)0;
|
||||
Scope *scope = sb->getMap();
|
||||
Address addr = sb->getAddress(vn->getOffset(),in0->getSize(),op->getAddr());
|
||||
if (addr.isInvalid())
|
||||
throw LowlevelError("Unable to generate proper address from spacebase");
|
||||
SymbolEntry *entry = scope->queryContainer(addr,1,Address());
|
||||
if (entry == (SymbolEntry *)0)
|
||||
return (Symbol *)0;
|
||||
int4 off = (int4)(addr.getOffset() - entry->getAddr().getOffset()) + entry->getOffset();
|
||||
vn->setSymbolReference(entry, off);
|
||||
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
|
||||
/// \param res is the container holding the result list of matching Varnodes
|
||||
void Funcdata::findLinkedVarnodes(SymbolEntry *entry,vector<Varnode *> &res) const
|
||||
|
||||
{
|
||||
if (entry->isDynamic()) {
|
||||
DynamicHash dhash;
|
||||
Varnode *vn = dhash.findVarnode(this,entry->getFirstUseAddress(),entry->getHash());
|
||||
if (vn != (Varnode *)0)
|
||||
res.push_back(vn);
|
||||
}
|
||||
else {
|
||||
VarnodeLocSet::const_iterator iter = beginLoc(entry->getSize(),entry->getAddr());
|
||||
VarnodeLocSet::const_iterator enditer = endLoc(entry->getSize(),entry->getAddr());
|
||||
for(;iter!=enditer;++iter) {
|
||||
Varnode *vn = *iter;
|
||||
Address addr = vn->getUsePoint(*this);
|
||||
if (entry->inUse(addr)) {
|
||||
res.push_back(vn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// If a Symbol is already attached, no change is made. Otherwise a special \e dynamic Symbol is
|
||||
/// created that is associated with the Varnode via a hash of its local data-flow (rather
|
||||
/// than its storage address).
|
||||
|
@ -994,7 +1111,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
|
||||
|
@ -1015,23 +1132,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;
|
||||
return true;
|
||||
else if (entry->getSize() == vn->getSize()) {
|
||||
if (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)
|
||||
|
|
|
@ -314,7 +314,7 @@ void DecompileAt::rawAction(void)
|
|||
ParamIDAnalysis pidanalysis( fd, false );
|
||||
pidanalysis.saveXml( sout, true );
|
||||
}
|
||||
fd->saveXml(sout,ghidra->getSendSyntaxTree());
|
||||
fd->saveXml(sout,0,ghidra->getSendSyntaxTree());
|
||||
if (ghidra->getSendCCode()&&
|
||||
(ghidra->allacts.getCurrentName() == "decompile"))
|
||||
ghidra->print->docFunction(fd);
|
||||
|
|
|
@ -1270,6 +1270,7 @@ void IfcTypeVarnode::execute(istream &s)
|
|||
scope = dcp->fd->getScopeLocal(); // force it to be in function scope
|
||||
Symbol *sym = scope->addSymbol(name,ct,loc,pc)->getSymbol();
|
||||
scope->setAttribute(sym,Varnode::typelock);
|
||||
sym->setIsolated(true);
|
||||
if (name.size() > 0)
|
||||
scope->setAttribute(sym,Varnode::namelock);
|
||||
|
||||
|
|
|
@ -103,6 +103,15 @@ bool Merge::mergeTestRequired(HighVariable *high_out,HighVariable *high_in)
|
|||
else if (high_out->isExtraOut())
|
||||
return false;
|
||||
|
||||
Symbol *symbolIn = high_in->getSymbol();
|
||||
Symbol *symbolOut = high_out->getSymbol();
|
||||
if (symbolIn != (Symbol *) 0 && symbolOut != (Symbol *) 0) {
|
||||
if (symbolIn != symbolOut)
|
||||
return false; // Map to different symbols
|
||||
if (high_in->getSymbolOffset() != high_out->getSymbolOffset())
|
||||
return false; // Map to different parts of same symbol
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -136,6 +145,14 @@ bool Merge::mergeTestAdjacent(HighVariable *high_out,HighVariable *high_in)
|
|||
Varnode *vn = high_in->getInputVarnode();
|
||||
if (vn->isIllegalInput()&&(!vn->isIndirectOnly())) return false;
|
||||
}
|
||||
Symbol *symbol = high_in->getSymbol();
|
||||
if (symbol != (Symbol *)0)
|
||||
if (symbol->isIsolated())
|
||||
return false;
|
||||
symbol = high_out->getSymbol();
|
||||
if (symbol != (Symbol *)0)
|
||||
if (symbol->isIsolated())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -151,9 +168,6 @@ bool Merge::mergeTestSpeculative(HighVariable *high_out,HighVariable *high_in)
|
|||
{
|
||||
if (!mergeTestAdjacent(high_out,high_in)) return false;
|
||||
|
||||
// Don't merge a mapped variable speculatively
|
||||
if (high_out->isMapped()) return false;
|
||||
if (high_in->isMapped()) return false;
|
||||
// Don't merge anything with a global speculatively
|
||||
if (high_out->isPersist()) return false;
|
||||
if (high_in->isPersist()) return false;
|
||||
|
@ -268,7 +282,7 @@ void Merge::mergeOpcode(OpCode opc)
|
|||
vn2 = op->getIn(j);
|
||||
if (!mergeTestBasic(vn2)) continue;
|
||||
if (mergeTestRequired(vn1->getHigh(),vn2->getHigh()))
|
||||
merge(vn1->getHigh(),vn2->getHigh(),false);
|
||||
merge(vn1->getHigh(),vn2->getHigh(),false); // This is a required merge
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -798,6 +812,67 @@ void Merge::mergeMarker(void)
|
|||
}
|
||||
}
|
||||
|
||||
/// \brief Merge together Varnodes mapped to SymbolEntrys from the same Symbol
|
||||
///
|
||||
/// Symbols that have more than one SymbolEntry may attach to more than one Varnode.
|
||||
/// These Varnodes need to be merged to properly represent a single variable.
|
||||
void Merge::mergeMultiEntry(void)
|
||||
|
||||
{
|
||||
SymbolNameTree::const_iterator iter = data.getScopeLocal()->beginMultiEntry();
|
||||
SymbolNameTree::const_iterator enditer = data.getScopeLocal()->endMultiEntry();
|
||||
for(;iter!=enditer;++iter) {
|
||||
vector<Varnode *> mergeList;
|
||||
Symbol *symbol = *iter;
|
||||
int4 numEntries = symbol->numEntries();
|
||||
int4 mergeCount = 0;
|
||||
int4 skipCount = 0;
|
||||
int4 conflictCount = 0;
|
||||
for(int4 i=0;i<numEntries;++i) {
|
||||
int4 prevSize = mergeList.size();
|
||||
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();
|
||||
updateHigh(high);
|
||||
for(int4 i=0;i<mergeList.size();++i) {
|
||||
HighVariable *newHigh = mergeList[i]->getHigh();
|
||||
if (newHigh == high) continue; // Varnodes already merged
|
||||
updateHigh(newHigh);
|
||||
if (!mergeTestRequired(high, newHigh)) {
|
||||
symbol->setMergeProblems();
|
||||
newHigh->setUnmerged();
|
||||
conflictCount += 1;
|
||||
continue;
|
||||
}
|
||||
if (!merge(high,newHigh,false)) { // Attempt the merge
|
||||
symbol->setMergeProblems();
|
||||
newHigh->setUnmerged();
|
||||
conflictCount += 1;
|
||||
continue;
|
||||
}
|
||||
mergeCount += 1;
|
||||
}
|
||||
if (skipCount != 0 || conflictCount !=0) {
|
||||
ostringstream s;
|
||||
s << "Unable to";
|
||||
if (mergeCount != 0)
|
||||
s << " fully";
|
||||
s << " merge symbol: " << symbol->getName();
|
||||
if (skipCount > 0)
|
||||
s << " -- Some instance varnodes not found.";
|
||||
if (conflictCount > 0)
|
||||
s << " -- Some merges are forbidden";
|
||||
data.warningHeader(s.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Speculatively merge Varnodes that are input/output to the same p-code op
|
||||
///
|
||||
/// If a single p-code op has an input and output HighVariable that share the same data-type,
|
||||
|
@ -1048,7 +1123,7 @@ void Merge::buildDominantCopy(HighVariable *high,vector<PcodeOp *> ©,int4 po
|
|||
}
|
||||
}
|
||||
if (count > 0 && domCopyIsNew) {
|
||||
high->merge(domVn->getHigh(),false);
|
||||
high->merge(domVn->getHigh(),true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -125,6 +125,7 @@ public:
|
|||
void mergeAddrTied(void);
|
||||
void mergeMarker(void);
|
||||
void mergeAdjacent(void);
|
||||
void mergeMultiEntry(void);
|
||||
bool hideShadows(HighVariable *high);
|
||||
void processCopyTrims(void);
|
||||
void markInternalCopies(void);
|
||||
|
|
|
@ -97,7 +97,7 @@ public:
|
|||
InjectPayload(const string &nm,int4 tp) { name=nm; type=tp; paramshift=0; dynamic = false; incidentalCopy = false; } ///< Construct for use with restoreXml
|
||||
int4 getParamShift(void) const { return paramshift; } ///< Get the number of parameters shifted
|
||||
bool isDynamic(void) const { return dynamic; } ///< Return \b true if p-code in the injection is generated dynamically
|
||||
bool isIncidentalCopy(void) const { return incidentalCopy; }
|
||||
bool isIncidentalCopy(void) const { return incidentalCopy; } ///< Return \b true if any injected COPY is considered \e incidental
|
||||
int4 sizeInput(void) const { return inputlist.size(); } ///< Return the number of input parameters
|
||||
int4 sizeOutput(void) const { return output.size(); } ///< Return the number of output parameters
|
||||
InjectParameter &getInput(int4 i) { return inputlist[i]; } ///< Get the i-th input parameter
|
||||
|
|
|
@ -770,16 +770,11 @@ void PrintC::opPtrsub(const PcodeOp *op)
|
|||
}
|
||||
}
|
||||
else if (ct->getMetatype() == TYPE_SPACEBASE) {
|
||||
TypeSpacebase *sb = (TypeSpacebase *)ct;
|
||||
Scope *scope = sb->getMap();
|
||||
Address addr = sb->getAddress(op->getIn(1)->getOffset(),in0->getSize(),op->getAddr());
|
||||
if (addr.isInvalid())
|
||||
throw LowlevelError("Unable to generate proper address from spacebase");
|
||||
SymbolEntry *entry = scope->queryContainer(addr,1,Address());
|
||||
Datatype *ct = (Datatype *)0;
|
||||
HighVariable *high = op->getIn(1)->getHigh();
|
||||
Symbol *symbol = high->getSymbol();
|
||||
arrayvalue = false;
|
||||
if (entry != (SymbolEntry *)0) {
|
||||
ct = entry->getSymbol()->getType();
|
||||
if (symbol != (Symbol *)0) {
|
||||
ct = symbol->getType();
|
||||
// The '&' is dropped if the output type is an array
|
||||
if (ct->getMetatype()==TYPE_ARRAY) {
|
||||
arrayvalue = valueon; // If printing value, use [0]
|
||||
|
@ -795,18 +790,21 @@ void PrintC::opPtrsub(const PcodeOp *op)
|
|||
if (arrayvalue)
|
||||
pushOp(&subscript,op);
|
||||
}
|
||||
if (entry == (SymbolEntry *)0)
|
||||
if (symbol == (Symbol *)0) {
|
||||
TypeSpacebase *sb = (TypeSpacebase *)ct;
|
||||
Address addr = sb->getAddress(op->getIn(1)->getOffset(),in0->getSize(),op->getAddr());
|
||||
pushUnnamedLocation(addr,(Varnode *)0,op);
|
||||
}
|
||||
else {
|
||||
int4 off = (int4)(addr.getOffset() - entry->getAddr().getOffset()) + entry->getOffset();
|
||||
int4 off = high->getSymbolOffset();
|
||||
if (off == 0)
|
||||
pushSymbol(entry->getSymbol(),(Varnode *)0,op);
|
||||
pushSymbol(symbol,(Varnode *)0,op);
|
||||
else {
|
||||
// If this "value" is getting used as a storage location
|
||||
// we can't use a cast in its description, so turn off
|
||||
// casting when printing the partial symbol
|
||||
// Datatype *exttype = ((mods & print_store_value)!=0) ? (Datatype *)0 : ct;
|
||||
pushPartialSymbol(entry->getSymbol(),off,0,(Varnode *)0,op,(Datatype *)0);
|
||||
pushPartialSymbol(symbol,off,0,(Varnode *)0,op,(Datatype *)0);
|
||||
}
|
||||
}
|
||||
if (arrayvalue)
|
||||
|
@ -1641,6 +1639,21 @@ void PrintC::pushSymbol(const Symbol *sym,const Varnode *vn,const PcodeOp *op)
|
|||
else
|
||||
tokenColor = EmitXml::var_color;
|
||||
// FIXME: resolve scopes
|
||||
if (sym->hasMergeProblems() && vn != (Varnode *)0) {
|
||||
HighVariable *high = vn->getHigh();
|
||||
if (high->isUnmerged()) {
|
||||
ostringstream s;
|
||||
s << sym->getName();
|
||||
SymbolEntry *entry = high->getSymbolEntry();
|
||||
if (entry != (SymbolEntry *)0) {
|
||||
s << '$' << dec << entry->getSymbol()->getMapEntryPosition(entry);
|
||||
}
|
||||
else
|
||||
s << "$$";
|
||||
pushAtom(Atom(s.str(),vartoken,tokenColor,op,vn));
|
||||
return;
|
||||
}
|
||||
}
|
||||
pushAtom(Atom(sym->getName(),vartoken,tokenColor,op,vn));
|
||||
}
|
||||
|
||||
|
@ -2182,21 +2195,27 @@ bool PrintC::emitScopeVarDecls(const Scope *scope,int4 cat)
|
|||
MapIterator iter = scope->begin();
|
||||
MapIterator enditer = scope->end();
|
||||
for(;iter!=enditer;++iter) {
|
||||
if ((*iter)->isPiece()) continue; // Don't do a partial entry
|
||||
Symbol *sym = (*iter)->getSymbol();
|
||||
const SymbolEntry *entry = *iter;
|
||||
if (entry->isPiece()) continue; // Don't do a partial entry
|
||||
Symbol *sym = entry->getSymbol();
|
||||
if (sym->getCategory() != cat) continue;
|
||||
if (sym->getName().size() == 0) continue;
|
||||
if (dynamic_cast<FunctionSymbol *>(sym) != (FunctionSymbol *)0)
|
||||
continue;
|
||||
if (dynamic_cast<LabSymbol *>(sym) != (LabSymbol *)0)
|
||||
continue;
|
||||
if (sym->isMultiEntry()) {
|
||||
if (sym->getFirstWholeMap() != entry)
|
||||
continue; // Only emit the first SymbolEntry for declaration of multi-entry Symbol
|
||||
}
|
||||
notempty = true;
|
||||
emitVarDeclStatement(sym);
|
||||
}
|
||||
list<SymbolEntry>::const_iterator iter_d = scope->beginDynamic();
|
||||
list<SymbolEntry>::const_iterator enditer_d = scope->endDynamic();
|
||||
for(;iter_d!=enditer_d;++iter_d) {
|
||||
if ((*iter_d).isPiece()) continue; // Don't do a partial entry
|
||||
const SymbolEntry *entry = &(*iter_d);
|
||||
if (entry->isPiece()) continue; // Don't do a partial entry
|
||||
Symbol *sym = (*iter_d).getSymbol();
|
||||
if (sym->getCategory() != cat) continue;
|
||||
if (sym->getName().size() == 0) continue;
|
||||
|
@ -2204,6 +2223,10 @@ bool PrintC::emitScopeVarDecls(const Scope *scope,int4 cat)
|
|||
continue;
|
||||
if (dynamic_cast<LabSymbol *>(sym) != (LabSymbol *)0)
|
||||
continue;
|
||||
if (sym->isMultiEntry()) {
|
||||
if (sym->getFirstWholeMap() != entry)
|
||||
continue;
|
||||
}
|
||||
notempty = true;
|
||||
emitVarDeclStatement(sym);
|
||||
}
|
||||
|
|
|
@ -1884,9 +1884,9 @@ int4 RuleDoubleShift::applyOp(PcodeOp *op,Funcdata &data)
|
|||
}
|
||||
|
||||
/// \class RuleDoubleArithShift
|
||||
/// \brief Simply two sequential INT_SRIGHT: `(x s>> #c) s>> #d => x s>> saturate(#c + #d)`
|
||||
/// \brief Simplify two sequential INT_SRIGHT: `(x s>> #c) s>> #d => x s>> saturate(#c + #d)`
|
||||
///
|
||||
/// Optimized division optimization in particular can produce a sequence of signed right shifts.
|
||||
/// Division optimization in particular can produce a sequence of signed right shifts.
|
||||
/// The shift amounts add up to the point where the sign bit has saturated the entire result.
|
||||
void RuleDoubleArithShift::getOpList(vector<uint4> &oplist) const
|
||||
|
||||
|
|
|
@ -97,12 +97,12 @@ public:
|
|||
LanedIterator(const LanedRegister *lanedR) { size = 0; mask = lanedR->sizeBitMask; normalize(); } ///< Constructor
|
||||
LanedIterator(void) { size = -1; mask = 0; } ///< Constructor for ending iterator
|
||||
LanedIterator &operator++(void) { size += 1; normalize(); return *this; } ///< Preincrement operator
|
||||
int4 operator*(void) const { return size; } /// Dereference operator
|
||||
int4 operator*(void) const { return size; } ///< Dereference operator
|
||||
LanedIterator &operator=(const LanedIterator &op2) { size = op2.size; mask = op2.mask; return *this; } ///< Assignment
|
||||
bool operator==(const LanedIterator &op2) const { return (size == op2.size); } ///< Equal operator
|
||||
bool operator!=(const LanedIterator &op2) const { return (size != op2.size); } ///< Not-equal operator
|
||||
};
|
||||
typedef LanedIterator const_iterator;
|
||||
typedef LanedIterator const_iterator; ///< Iterator over possible lane sizes for this register
|
||||
private:
|
||||
int4 wholeSize; ///< Size of the whole register
|
||||
uint4 sizeBitMask; ///< A 1-bit for every permissible lane size
|
||||
|
|
|
@ -23,13 +23,57 @@ HighVariable::HighVariable(Varnode *vn)
|
|||
|
||||
{
|
||||
numMergeClasses = 1;
|
||||
highflags = HighVariable::flagsdirty | HighVariable::typedirty | HighVariable::coverdirty;
|
||||
highflags = flagsdirty | namerepdirty | typedirty | coverdirty;
|
||||
flags = 0;
|
||||
type = (Datatype *)0;
|
||||
symbol = (Symbol *)0;
|
||||
nameRepresentative = (Varnode *)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
|
||||
/// \param 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 +82,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 +97,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 +109,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 +142,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 +154,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
|
||||
|
@ -168,18 +230,22 @@ bool HighVariable::compareName(Varnode *vn1,Varnode *vn2)
|
|||
Varnode *HighVariable::getNameRepresentative(void) const
|
||||
|
||||
{
|
||||
if ((highflags & namerepdirty)==0)
|
||||
return nameRepresentative; // Name representative is up to date
|
||||
highflags &= ~namerepdirty;
|
||||
|
||||
vector<Varnode *>::const_iterator iter;
|
||||
Varnode *rep,*vn;
|
||||
Varnode *vn;
|
||||
|
||||
iter = inst.begin();
|
||||
rep = *iter;
|
||||
nameRepresentative = *iter;
|
||||
++iter;
|
||||
for(;iter!=inst.end();++iter) {
|
||||
vn = *iter;
|
||||
if (compareName(rep,vn))
|
||||
rep = vn;
|
||||
if (compareName(nameRepresentative,vn))
|
||||
nameRepresentative = vn;
|
||||
}
|
||||
return rep;
|
||||
return nameRepresentative;
|
||||
}
|
||||
|
||||
/// Search for the given Varnode and cut it out of the list, marking all properties as \e dirty.
|
||||
|
@ -193,12 +259,28 @@ 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|namerepdirty|coverdirty|typedirty);
|
||||
if (vn->getSymbolEntry() != (SymbolEntry *)0)
|
||||
highflags |= symboldirty;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Assuming there is a Symbol attached to \b this, run through the Varnode members
|
||||
/// until we find one with a SymbolEntry corresponding to the Symbol and return it.
|
||||
/// \return the SymbolEntry that mapped the Symbol to \b this or null if no Symbol is attached
|
||||
SymbolEntry *HighVariable::getSymbolEntry(void) const
|
||||
|
||||
{
|
||||
for(int4 i=0;i<inst.size();++i) {
|
||||
SymbolEntry *entry = inst[i]->getSymbolEntry();
|
||||
if (entry != (SymbolEntry *)0 && entry->getSymbol() == symbol)
|
||||
return entry;
|
||||
}
|
||||
return (SymbolEntry *)0;
|
||||
}
|
||||
|
||||
/// The data-type its dirtying mechanism is disabled. The data-type will not change, unless
|
||||
/// this method is called again.
|
||||
/// \param tp is the data-type to set
|
||||
|
@ -219,12 +301,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|namerepdirty|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 +330,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;
|
||||
}
|
||||
|
@ -359,6 +443,46 @@ int4 HighVariable::instanceIndex(const Varnode *vn) const
|
|||
return -1;
|
||||
}
|
||||
|
||||
/// \param s is the output stream to write XML to
|
||||
void HighVariable::saveXml(ostream &s) const
|
||||
|
||||
{
|
||||
Varnode *vn = getNameRepresentative(); // Get representative varnode
|
||||
s << "<high ";
|
||||
// a_v(s,"name",high->getName());
|
||||
a_v_u(s,"repref",vn->getCreateIndex());
|
||||
if (isSpacebase()||isImplied()) // This is a special variable
|
||||
a_v(s,"class",string("other"));
|
||||
else if (isPersist()&&isAddrTied()) // Global variable
|
||||
a_v(s,"class",string("global"));
|
||||
else if (isConstant())
|
||||
a_v(s,"class",string("constant"));
|
||||
else if (!isPersist() && (symbol != (Symbol *)0)) {
|
||||
if (symbol->getCategory() == 0)
|
||||
a_v(s,"class",string("param"));
|
||||
else
|
||||
a_v(s,"class",string("local"));
|
||||
}
|
||||
else {
|
||||
a_v(s,"class",string("other"));
|
||||
}
|
||||
if (isTypeLock())
|
||||
a_v_b(s,"typelock",true);
|
||||
if (symbol != (Symbol *)0) {
|
||||
a_v_u(s,"symref",symbol->getId());
|
||||
if (symboloffset >= 0)
|
||||
a_v_i(s, "offset", symboloffset);
|
||||
}
|
||||
s << '>';
|
||||
getType()->saveXml(s);
|
||||
for(int4 j=0;j<inst.size();++j) {
|
||||
s << "<addr ";
|
||||
a_v_u(s,"ref",inst[j]->getCreateIndex());
|
||||
s << "/>";
|
||||
}
|
||||
s << "</high>";
|
||||
}
|
||||
|
||||
#ifdef MERGEMULTI_DEBUG
|
||||
/// \brief Check that there are no internal Cover intersections within \b this
|
||||
///
|
||||
|
|
|
@ -44,19 +44,24 @@ public:
|
|||
/// So we keep track of when these inherited values are \e dirty
|
||||
enum {
|
||||
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
|
||||
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
|
||||
namerepdirty = 2, ///< The name representative for the HighVariable is dirty
|
||||
typedirty = 4, ///< The data-type for the HighVariable is dirty
|
||||
coverdirty = 8, ///< The cover for the HighVariable is dirty
|
||||
symboldirty = 0x10, ///< The symbol attachment is dirty
|
||||
copy_in1 = 0x20, ///< There exists at least 1 COPY into \b this HighVariable from other HighVariables
|
||||
copy_in2 = 0x40, ///< There exists at least 2 COPYs into \b this HighVariable from other HighVariables
|
||||
type_finalized = 0x80, ///< Set if a final data-type is locked in and dirtying is disabled
|
||||
unmerged = 0x100 ///< Set if part of a multi-entry Symbol but did not get merged with other SymbolEntrys
|
||||
};
|
||||
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
|
||||
mutable uint4 highflags; ///< Dirtiness flags
|
||||
mutable uint4 flags; ///< Boolean properties inherited from Varnode members
|
||||
mutable Datatype *type; ///< The data-type for this
|
||||
mutable Datatype *type; ///< The data-type for \b this
|
||||
mutable Varnode *nameRepresentative; ///< The storage location used to generate a Symbol name
|
||||
mutable Cover wholecover; ///< The ranges of code addresses covered by this HighVariable
|
||||
mutable Symbol *symbol; ///< The Symbol \b this HighVariable is tied to
|
||||
mutable int4 symboloffset; ///< -1=perfect symbol match >=0, offset
|
||||
|
@ -64,34 +69,28 @@ 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
|
||||
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 |= flagsdirty | namerepdirty; } ///< Mark the boolean properties as \e dirty
|
||||
void coverDirty(void) const { highflags |= coverdirty; } ///< Mark the cover as \e dirty
|
||||
void typeDirty(void) const { highflags |= typedirty; } ///< Mark the data-type as \e dirty
|
||||
void setUnmerged(void) const { highflags |= unmerged; } ///< Mark \b this as having merge problems
|
||||
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
|
||||
Symbol *getSymbol(void) const { updateSymbol(); return symbol; } ///< Get the Symbol associated with \b this or null
|
||||
SymbolEntry *getSymbolEntry(void) const; /// Get the SymbolEntry mapping to \b this or null
|
||||
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 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
|
||||
void finalizeDatatype(Datatype *tp); ///< Set a final datatype for \b this variable
|
||||
|
||||
/// \brief Print details of the cover for \b this (for debug purposes)
|
||||
|
@ -117,6 +116,7 @@ public:
|
|||
void setMark(void) const { flags |= Varnode::mark; } ///< Set the mark on this variable
|
||||
void clearMark(void) const { flags &= ~Varnode::mark; } ///< Clear the mark on this variable
|
||||
bool isMark(void) const { return ((flags&Varnode::mark)!=0); } ///< Return \b true if \b this is marked
|
||||
bool isUnmerged(void) const { return ((highflags&unmerged)!=0); } ///< Return \b true if \b this has merge problems
|
||||
|
||||
/// \brief Determine if \b this HighVariable has an associated cover.
|
||||
///
|
||||
|
@ -129,6 +129,7 @@ public:
|
|||
bool isUnattached(void) const { return inst.empty(); } ///< Return \b true if \b this has no member Varnode
|
||||
bool isTypeLock(void) const { updateType(); return ((flags & Varnode::typelock)!=0); } ///< Return \b true if \b this is \e typelocked
|
||||
bool isNameLock(void) const { updateFlags(); return ((flags & Varnode::namelock)!=0); } ///< Return \b true if \b this is \e namelocked
|
||||
void saveXml(ostream &s) const; ///< Save the variable to stream as an XML \<high\> tag
|
||||
#ifdef MERGEMULTI_DEBUG
|
||||
void verifyCover(void) const;
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
|
@ -305,7 +272,6 @@ ScopeLocal::ScopeLocal(AddrSpace *spc,Funcdata *fd,Architecture *g) : ScopeInter
|
|||
rangeLocked = false;
|
||||
stackGrowsNegative = true;
|
||||
restrictScope(fd);
|
||||
dedupId = fd->getAddress().getOffset(); // Allow multiple scopes with same name
|
||||
}
|
||||
|
||||
/// Turn any symbols that are \e name \e locked but not \e type \e locked into name recommendations
|
||||
|
@ -322,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -447,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)) {
|
||||
|
@ -521,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
|
||||
|
@ -1221,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);
|
||||
|
@ -1234,48 +1174,96 @@ 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;
|
||||
if ((sym->getFlags() & Varnode::addrtied)!=0)
|
||||
continue; // Cannot use untied varnode as primary map for address tied symbol
|
||||
SymbolEntry *entry = sym->getFirstWholeMap();
|
||||
// entry->getAddr() does not need to match address of the recommendation
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1290,38 +1278,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);
|
||||
}
|
||||
|
|
|
@ -21,26 +21,28 @@
|
|||
|
||||
#include "database.hh"
|
||||
|
||||
/// \brief An Address pair with a point of use
|
||||
/// \brief A symbol name recommendation with its associated storage location
|
||||
///
|
||||
/// 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 {
|
||||
/// The name is associated with a static Address and use point in the code. Symbols
|
||||
/// present at the end of function decompilation without a name can acquire \b this name
|
||||
/// if their storage matches.
|
||||
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
|
||||
/// \brief A name recommendation for a particular dynamic storage location
|
||||
///
|
||||
/// A recommendation for a symbol name whose storage is dynamic. The storage
|
||||
/// is identified using the DynamicHash mechanism and may or may not exist.
|
||||
|
@ -48,15 +50,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 +182,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 +191,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 +217,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
|
||||
|
|
|
@ -360,6 +360,54 @@ 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
|
||||
/// \return \b true if any properties have changed
|
||||
bool Varnode::setSymbolProperties(SymbolEntry *entry)
|
||||
|
||||
{
|
||||
bool res = entry->updateType(this);
|
||||
if (entry->getSymbol()->isTypeLocked()) {
|
||||
if (mapentry != entry) {
|
||||
mapentry = entry;
|
||||
if (high != (HighVariable *)0)
|
||||
high->setSymbol(this);
|
||||
res = true;
|
||||
}
|
||||
}
|
||||
setFlags(entry->getAllFlags() & ~Varnode::typelock);
|
||||
return res;
|
||||
}
|
||||
|
||||
/// 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;
|
||||
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);
|
||||
}
|
||||
|
||||
/// 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 +442,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
|
||||
bool 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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue