Refactoring MapRange to RangeHint

This commit is contained in:
caheckman 2019-06-16 16:47:13 -04:00
parent 12c655f41f
commit f825b1aa57
2 changed files with 224 additions and 216 deletions

View file

@ -49,19 +49,19 @@ bool AddressUsePointPair::operator==(const AddressUsePointPair &op2) const
return (useaddr == op2.useaddr); return (useaddr == op2.useaddr);
} }
/// \brief Can the given intersecting MapRange coexist with \b this at their given offsets /// \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 /// Determine if the data-type information in the two ranges \e line \e up
/// properly, in which case the union of the two ranges can exist without /// properly, in which case the union of the two ranges can exist without
/// destroying data-type information. /// destroying data-type information.
/// \param b is the range to reconcile with \b this /// \param b is the range to reconcile with \b this
/// \param \b true if the data-type information can be reconciled /// \param \b true if the data-type information can be reconciled
bool MapRange::reconcile(const MapRange *b) const bool RangeHint::reconcile(const RangeHint *b) const
{ {
const MapRange *a = this; const RangeHint *a = this;
if (a->type->getSize() < b->type->getSize()) { if (a->type->getSize() < b->type->getSize()) {
const MapRange *tmp = b; const RangeHint *tmp = b;
b = a; // Make sure b is smallest b = a; // Make sure b is smallest
a = tmp; a = tmp;
} }
@ -86,7 +86,7 @@ bool MapRange::reconcile(const MapRange *b) const
/// and that the two ranges intersect. /// and that the two ranges intersect.
/// \param b is the given range to check for containment with \b this /// \param b is the given range to check for containment with \b this
/// \return \b true if one contains the other /// \return \b true if one contains the other
bool MapRange::contain(const MapRange *b) const bool RangeHint::contain(const RangeHint *b) const
{ {
if (sstart == b->sstart) return true; if (sstart == b->sstart) return true;
@ -103,7 +103,7 @@ bool MapRange::contain(const MapRange *b) const
/// \param b is the other given range /// \param b is the other given range
/// \param reconcile is \b true is the two ranges have \e reconciled data-types /// \param reconcile is \b true is the two ranges have \e reconciled data-types
/// \return \b true if the \b this ranges's data-type is preferred /// \return \b true if the \b this ranges's data-type is preferred
bool MapRange::preferred(const MapRange *b,bool reconcile) const bool RangeHint::preferred(const RangeHint *b,bool reconcile) const
{ {
if (start != b->start) if (start != b->start)
@ -117,15 +117,167 @@ bool MapRange::preferred(const MapRange *b,bool reconcile) const
return true; return true;
if (!reconcile) { // If the ranges don't reconcile if (!reconcile) { // If the ranges don't reconcile
if ((rangeType == MapRange::open)&&(b->rangeType != MapRange::open)) // Throw out the open range if ((rangeType == RangeHint::open)&&(b->rangeType != RangeHint::open)) // Throw out the open range
return false; return false;
if ((b->rangeType == MapRange::open)&&(rangeType != MapRange::open)) if ((b->rangeType == RangeHint::open)&&(rangeType != RangeHint::open))
return true; return true;
} }
return (0>type->typeOrder(*b->type)); // Prefer the more specific return (0>type->typeOrder(*b->type)); // Prefer the more specific
} }
/// If \b this RangeHint is an array and the following details line up, adjust \b this
/// so that it \e absorbs the other given RangeHint and return \b true.
/// The second RangeHint:
/// - must have the same element size
/// - must have close to the same data-type
/// - must line up with the step of the first array
/// - must not be a locked data-type
/// - must not extend the size of the first array beyond what is known of its limits
///
/// \param b is the other RangeHint to absorb
/// \return \b true if the other RangeHint was successfully absorbed
bool RangeHint::absorb(RangeHint *b)
{
if (rangeType != RangeHint::open) return false;
if (highind < 0) return false;
if (b->rangeType == RangeHint::endpoint) return false; // Don't merge with bounding range
Datatype *settype = type;
if (settype->getSize() != b->type->getSize()) return false;
if (settype->getMetatype() == TYPE_UNKNOWN)
settype = b->type;
else if (b->type->getMetatype() == TYPE_UNKNOWN) {
}
else if (settype->getMetatype() == TYPE_INT && b->type->getMetatype() == TYPE_UINT) {
}
else if (settype->getMetatype() == TYPE_UINT && b->type->getMetatype() == TYPE_INT) {
}
else if (settype != b->type) // If they are both not unknown, they must be the same
return false;
if ((flags & Varnode::typelock)!=0) return false;
if ((b->flags & Varnode::typelock)!=0) return false;
if (flags != b->flags) return false;
intb diffsz = b->sstart - sstart;
if ((diffsz % settype->getSize()) != 0) return false;
diffsz /= settype->getSize();
if (diffsz > highind) return false;
type = settype;
if (b->rangeType == RangeHint::open && (0 <= b->highind)) { // If b has array indexing
int4 trialhi = b->highind + diffsz;
if (highind < trialhi)
highind = trialhi;
}
return true;
}
/// Given that \b this and the other RangeHint intersect, redefine \b this so that it
/// becomes the union of the two original ranges. The union must succeed in some form.
/// An attempt is made to preserve the data-type information of both the original ranges,
/// but changes will be made if necessary. An exception is thrown if the data-types
/// are locked and cannot be reconciled.
/// \param b is the other RangeHint to merge with \b this
/// \param space is the address space holding the ranges
/// \param typeFactory is a factory for producing data-types
/// \return \b true if there was an overlap that could be reconciled
bool RangeHint::merge(RangeHint *b,AddrSpace *space,TypeFactory *typeFactory)
{
uintb aend,bend;
uintb end;
Datatype *resType;
uint4 resFlags;
bool didReconcile;
int4 resHighIndex;
bool overlapProblems = false;
aend = space->wrapOffset(start+size);
bend = space->wrapOffset(b->start+b->size);
RangeHint::RangeType resRangeType = RangeHint::fixed;
resHighIndex = -1;
if ((aend==0)||(bend==0))
end = 0;
else
end = (aend > bend) ? aend : bend;
if (contain(b)) { // Does one range contain the other
didReconcile = reconcile(b); // Can the data-type layout be reconciled
if (preferred(b,didReconcile)) { // If a's data-type is preferred over b
resType = type;
resFlags = flags;
resRangeType = rangeType;
resHighIndex = highind;
}
else {
resType = b->type;
resFlags = b->flags;
resRangeType = b->rangeType;
resHighIndex = b->highind;
}
if ((start==b->start)&&(size==b->size)) {
resRangeType = (rangeType==RangeHint::open || b->rangeType==RangeHint::open) ? RangeHint::open : RangeHint::fixed;
if (resRangeType == RangeHint::open)
resHighIndex = (highind < b->highind) ? b->highind : highind;
}
if (!didReconcile) { // See if two types match up
if ((b->rangeType != RangeHint::open)&&(rangeType != RangeHint::open))
overlapProblems = true;
}
}
else {
didReconcile = false;
resType = (Datatype *)0; // Unable to resolve the type
resFlags = 0;
}
// Check for really problematic cases
if (!didReconcile) {
if ((b->flags & Varnode::typelock)!=0) {
if ((flags & Varnode::typelock)!=0)
throw LowlevelError("Overlapping forced variable types : " + type->getName() + " " + b->type->getName());
}
}
if (resType == (Datatype *)0) // If all else fails
resType = typeFactory->getBase(1,TYPE_UNKNOWN); // Do unknown array (size 1)
type = resType;
flags = resFlags;
rangeType = resRangeType;
highind = resHighIndex;
if ((!didReconcile)&&(start != b->start)) { // Truncation is forced
if ((flags & Varnode::typelock)!=0) { // If a is locked
return overlapProblems; // Discard b entirely in favor of a
}
// Concede confusion about types, set unknown type rather than a or b's type
size = space->wrapOffset(end-start);
type = typeFactory->getBase(size,TYPE_UNKNOWN);
flags = 0;
rangeType = RangeHint::fixed;
highind = -1;
return overlapProblems;
}
size = resType->getSize();
return overlapProblems;
}
/// Order the two ranges by the signed version of their offset, then by size,
/// then by data-type
/// \param a is the first range to compare
/// \param b is the second range
/// \return \b true if the first range is ordered before the second
bool RangeHint::compareRanges(const RangeHint *a,const RangeHint *b)
{
if (a->sstart != b->sstart)
return (a->sstart < b->sstart);
if (a->size != b->size)
return (a->size < b->size); // Small sizes come first
type_metatype ameta = a->type->getMetatype();
type_metatype bmeta = b->type->getMetatype();
if (ameta != bmeta)
return (ameta < bmeta); // Order more specific types first
return true;
}
/// \param spc is the (stack) address space associated with this function's local variables /// \param spc is the (stack) address space associated with this function's local variables
/// \param fd is the function associated with these local variables /// \param fd is the function associated with these local variables
/// \param g is the Architecture /// \param g is the Architecture
@ -135,7 +287,6 @@ ScopeLocal::ScopeLocal(AddrSpace *spc,Funcdata *fd,Architecture *g) : ScopeInter
space = spc; space = spc;
rangeLocked = false; rangeLocked = false;
stackGrowsNegative = true; stackGrowsNegative = true;
overlapProblems = false;
restrictScope(fd); restrictScope(fd);
dedupId = fd->getAddress().getOffset(); // Allow multiple scopes with same name dedupId = fd->getAddress().getOffset(); // Allow multiple scopes with same name
} }
@ -306,11 +457,11 @@ string ScopeLocal::buildVariableName(const Address &addr,
return ScopeInternal::buildVariableName(addr,pc,ct,index,flags); return ScopeInternal::buildVariableName(addr,pc,ct,index,flags);
} }
/// Shrink the MapRange as necessary so that it fits in the mapped region of the Scope /// Shrink the RangeHint as necessary so that it fits in the mapped region of the Scope
/// and doesn't overlap any other Symbols. If this is not possible, return \b false. /// and doesn't overlap any other Symbols. If this is not possible, return \b false.
/// \param a is the given MapRange to fit /// \param a is the given RangeHint to fit
/// \return \b true if a valid adjustment was made /// \return \b true if a valid adjustment was made
bool ScopeLocal::adjustFit(MapRange &a) const bool ScopeLocal::adjustFit(RangeHint &a) const
{ {
if (a.size==0) return false; // Nothing to fit if (a.size==0) return false; // Nothing to fit
@ -337,10 +488,10 @@ bool ScopeLocal::adjustFit(MapRange &a) const
return true; return true;
} }
/// A name and final data-type is constructed for the MapRange, and they are entered as /// A name and final data-type is constructed for the RangeHint, and they are entered as
/// a new Symbol into \b this scope. /// a new Symbol into \b this scope.
/// \param a is the given MapRange to create a Symbol for /// \param a is the given RangeHint to create a Symbol for
void ScopeLocal::createEntry(const MapRange &a) void ScopeLocal::createEntry(const RangeHint &a)
{ {
Address addr(space,a.start); Address addr(space,a.start);
@ -356,25 +507,6 @@ void ScopeLocal::createEntry(const MapRange &a)
addSymbol(nm,ct,addr,usepoint); addSymbol(nm,ct,addr,usepoint);
} }
/// Order the two ranges by the signed version of their offset, then by size,
/// then by data-type
/// \param a is the first range to compare
/// \param b is the second range
/// \return \b true if the first range is ordered before the second
bool MapState::compareRanges(const MapRange *a,const MapRange *b)
{
if (a->sstart != b->sstart)
return (a->sstart < b->sstart);
if (a->size != b->size)
return (a->size < b->size); // Small sizes come first
type_metatype ameta = a->type->getMetatype();
type_metatype bmeta = b->type->getMetatype();
if (ameta != bmeta)
return (ameta < bmeta); // Order more specific types first
return true;
}
/// Set up basic offset boundaries for what constitutes a local variable /// Set up basic offset boundaries for what constitutes a local variable
/// or a parameter on the stack. This can be informed by the ProtoModel if available. /// or a parameter on the stack. This can be informed by the ProtoModel if available.
/// \param proto is the function prototype to use as a prototype model /// \param proto is the function prototype to use as a prototype model
@ -613,7 +745,7 @@ MapState::MapState(AddrSpace *spc,const RangeList &rn,
MapState::~MapState(void) MapState::~MapState(void)
{ {
vector<MapRange *>::iterator iter; vector<RangeHint *>::iterator iter;
for(iter=maplist.begin();iter!=maplist.end();++iter) for(iter=maplist.begin();iter!=maplist.end();++iter)
delete *iter; delete *iter;
} }
@ -625,7 +757,7 @@ MapState::~MapState(void)
/// \param fl is additional boolean properties /// \param fl is additional boolean properties
/// \param rt is the type of the hint /// \param rt is the type of the hint
/// \param hi is the biggest guaranteed index for \e open range hints /// \param hi is the biggest guaranteed index for \e open range hints
void MapState::addRange(uintb st,Datatype *ct,uint4 fl,MapRange::RangeType rt,int4 hi) void MapState::addRange(uintb st,Datatype *ct,uint4 fl,RangeHint::RangeType rt,int4 hi)
{ {
if ((ct == (Datatype *)0)||(ct->getSize()==0)) // Must have a real type if ((ct == (Datatype *)0)||(ct->getSize()==0)) // Must have a real type
@ -636,7 +768,7 @@ void MapState::addRange(uintb st,Datatype *ct,uint4 fl,MapRange::RangeType rt,in
intb sst = (intb)AddrSpace::byteToAddress(st,spaceid->getWordSize()); intb sst = (intb)AddrSpace::byteToAddress(st,spaceid->getWordSize());
sign_extend(sst,spaceid->getAddrSize()*8-1); sign_extend(sst,spaceid->getAddrSize()*8-1);
sst = (intb)AddrSpace::addressToByte(sst,spaceid->getWordSize()); sst = (intb)AddrSpace::addressToByte(sst,spaceid->getWordSize());
MapRange *range = new MapRange(st,sz,sst,ct,fl,rt,hi); RangeHint *range = new RangeHint(st,sz,sst,ct,fl,rt,hi);
maplist.push_back(range); maplist.push_back(range);
#ifdef OPACTION_DEBUG #ifdef OPACTION_DEBUG
if (debugon) { if (debugon) {
@ -650,7 +782,7 @@ void MapState::addRange(uintb st,Datatype *ct,uint4 fl,MapRange::RangeType rt,in
#endif #endif
} }
/// Run through all Symbols in the given map and create a corresponding MapRange hint /// Run through all Symbols in the given map and create a corresponding RangeHint
/// to \b this collection for each Symbol. /// to \b this collection for each Symbol.
/// \param rangemap is the given map of Symbols /// \param rangemap is the given map of Symbols
void MapState::gatherSymbols(const EntryMap *rangemap) void MapState::gatherSymbols(const EntryMap *rangemap)
@ -665,11 +797,11 @@ void MapState::gatherSymbols(const EntryMap *rangemap)
// if ((*iter).isPiece()) continue; // This should probably never happen // if ((*iter).isPiece()) continue; // This should probably never happen
uintb start = (*iter).getAddr().getOffset(); uintb start = (*iter).getAddr().getOffset();
Datatype *ct = sym->getType(); Datatype *ct = sym->getType();
addRange(start,ct,sym->getFlags(),MapRange::fixed,-1); addRange(start,ct,sym->getFlags(),RangeHint::fixed,-1);
} }
} }
/// Sort the collection and add a special terminating MapRange /// Sort the collection and add a special terminating RangeHint
/// \return \b true if the collection isn't empty (and iteration can begin) /// \return \b true if the collection isn't empty (and iteration can begin)
bool MapState::initialize(void) bool MapState::initialize(void)
@ -683,15 +815,15 @@ bool MapState::initialize(void)
sign_extend(sst,spaceid->getAddrSize()*8-1); sign_extend(sst,spaceid->getAddrSize()*8-1);
sst = (intb)AddrSpace::addressToByte(sst,spaceid->getWordSize()); sst = (intb)AddrSpace::addressToByte(sst,spaceid->getWordSize());
// Add extra range to bound any final open entry // Add extra range to bound any final open entry
MapRange *range = new MapRange(high,1,sst,defaultType,0,MapRange::endpoint,-2); RangeHint *range = new RangeHint(high,1,sst,defaultType,0,RangeHint::endpoint,-2);
maplist.push_back(range); maplist.push_back(range);
stable_sort(maplist.begin(),maplist.end(),compareRanges); stable_sort(maplist.begin(),maplist.end(),RangeHint::compareRanges);
iter = maplist.begin(); iter = maplist.begin();
return true; return true;
} }
/// Add a MapRange hint corresponding to each Varnode stored in the address space /// Add a RangeHint corresponding to each Varnode stored in the address space
/// for the given function. The current knowledge of the Varnode's data-type /// for the given function. The current knowledge of the Varnode's data-type
/// is included as part of the hint. /// is included as part of the hint.
/// \param fd is the given function /// \param fd is the given function
@ -710,11 +842,11 @@ void MapState::gatherVarnodes(const Funcdata &fd)
// Do not force Varnode flags on the entry // Do not force Varnode flags on the entry
// as the flags were inherited from the previous // as the flags were inherited from the previous
// (now obsolete) entry // (now obsolete) entry
addRange(start,ct,0,MapRange::fixed,-1); addRange(start,ct,0,RangeHint::fixed,-1);
} }
} }
/// Add a MapRange hint corresponding to each HighVariable that is mapped to our /// Add a RangeHint corresponding to each HighVariable that is mapped to our
/// address space for the given function. /// address space for the given function.
/// \param fd is the given function /// \param fd is the given function
void MapState::gatherHighs(const Funcdata &fd) void MapState::gatherHighs(const Funcdata &fd)
@ -737,14 +869,14 @@ void MapState::gatherHighs(const Funcdata &fd)
varvec.push_back(high); varvec.push_back(high);
uintb start = vn->getOffset(); uintb start = vn->getOffset();
Datatype *ct = high->getType(); // Get type from high Datatype *ct = high->getType(); // Get type from high
addRange(start,ct,0,MapRange::fixed,-1); addRange(start,ct,0,RangeHint::fixed,-1);
} }
for(int4 i=0;i<varvec.size();++i) for(int4 i=0;i<varvec.size();++i)
varvec[i]->clearMark(); varvec[i]->clearMark();
} }
/// For any Varnode that looks like a pointer into our address space, create an /// For any Varnode that looks like a pointer into our address space, create an
/// \e open MapRange hint. The size of the object may not be known. /// \e open RangeHint. The size of the object may not be known.
/// \param fd is the given function /// \param fd is the given function
void MapState::gatherOpen(const Funcdata &fd) void MapState::gatherOpen(const Funcdata &fd)
@ -773,7 +905,7 @@ void MapState::gatherOpen(const Funcdata &fd)
else { else {
minItems = -1; minItems = -1;
} }
addRange(offset,ct,0,MapRange::open,minItems); addRange(offset,ct,0,RangeHint::open,minItems);
} }
const list<LoadGuard> &loadGuard( fd.getLoadGuards() ); const list<LoadGuard> &loadGuard( fd.getLoadGuards() );
@ -803,10 +935,10 @@ void MapState::gatherOpen(const Funcdata &fd)
} }
if (guard.isRangeLocked()) { if (guard.isRangeLocked()) {
int4 minItems = ((guard.getMaximum() - guard.getMinimum()) + 1) / step; int4 minItems = ((guard.getMaximum() - guard.getMinimum()) + 1) / step;
addRange(guard.getMinimum(),ct,0,MapRange::open,minItems-1); addRange(guard.getMinimum(),ct,0,RangeHint::open,minItems-1);
} }
else else
addRange(guard.getMinimum(),ct,0,MapRange::open,3); addRange(guard.getMinimum(),ct,0,RangeHint::open,3);
} }
} }
@ -829,7 +961,7 @@ void ScopeLocal::restructureVarnode(bool aliasyes)
state.gatherVarnodes(*fd); // Gather stack type information from varnodes state.gatherVarnodes(*fd); // Gather stack type information from varnodes
state.gatherOpen(*fd); state.gatherOpen(*fd);
state.gatherSymbols(maptable[space->getIndex()]); state.gatherSymbols(maptable[space->getIndex()]);
restructure(state,false); restructure(state);
// At some point, processing mapped input symbols may be folded // At some point, processing mapped input symbols may be folded
// into the above gather/restructure process, but for now // into the above gather/restructure process, but for now
@ -860,167 +992,39 @@ void ScopeLocal::restructureHigh(void)
state.gatherHighs(*fd); // Gather stack type information from highs state.gatherHighs(*fd); // Gather stack type information from highs
state.gatherOpen(*fd); state.gatherOpen(*fd);
state.gatherSymbols(maptable[space->getIndex()]); state.gatherSymbols(maptable[space->getIndex()]);
restructure(state,true); bool overlapProblems = restructure(state);
if (overlapProblems) if (overlapProblems)
fd->warningHeader("Could not reconcile some variable overlaps"); fd->warningHeader("Could not reconcile some variable overlaps");
} }
/// If the first MapRange is an array and the following details line up, adjust the first MapRange /// RangeHints from the given collection are merged into a definitive set of Symbols
/// so that it \e absorbs the second and return \b true. /// for \b this scope. Overlapping or open RangeHints are adjusted to form a disjoint
/// The second MapRange:
/// - must have the same element size
/// - must have close to the same data-type
/// - must line up with the step of the first array
/// - must not be a locked data-type
/// - must not extend the size of the first array beyond what is known of its limits
///
/// \param a is the first MapRange
/// \param b is the second MapRange being absorbed
/// \return \b true if the second MapRange was successfully absorbed
bool ScopeLocal::rangeAbsorb(MapRange *a,MapRange *b)
{
if (a->rangeType != MapRange::open) return false;
if (a->highind < 0) return false;
if (b->rangeType == MapRange::endpoint) return false; // Don't merge with bounding range
Datatype *settype = a->type;
if (settype->getSize() != b->type->getSize()) return false;
if (settype->getMetatype() == TYPE_UNKNOWN)
settype = b->type;
else if (b->type->getMetatype() == TYPE_UNKNOWN) {
}
else if (settype->getMetatype() == TYPE_INT && b->type->getMetatype() == TYPE_UINT) {
}
else if (settype->getMetatype() == TYPE_UINT && b->type->getMetatype() == TYPE_INT) {
}
else if (settype != b->type) // If they are both not unknown, they must be the same
return false;
if ((a->flags & Varnode::typelock)!=0) return false;
if ((b->flags & Varnode::typelock)!=0) return false;
if (a->flags != b->flags) return false;
intb diffsz = b->sstart - a->sstart;
if ((diffsz % settype->getSize()) != 0) return false;
diffsz /= settype->getSize();
if (diffsz > a->highind) return false;
a->type = settype;
if (b->rangeType == MapRange::open && (0 <= b->highind)) { // If b has array indexing
int4 trialhi = b->highind + diffsz;
if (a->highind < trialhi)
a->highind = trialhi;
}
return true;
}
/// Given that the two MapRanges intersect, redefine the first MapRange so that it
/// becomes the union of the two original ranges. The union must succeed in some form.
/// An attempt is made to preserve the data-type information of both the original ranges,
/// but changes will be made if necessary. An exception is thrown if the data-types
/// are locked and cannot be reconciled.
/// \param a is the first given MapRange
/// \param b is the second given MapRange
/// \param warning is \b true if overlaps that cannot be reconciled should generate a warning comment
void ScopeLocal::rangeUnion(MapRange *a,MapRange *b,bool warning)
{
uintb aend,bend;
uintb end;
Datatype *restype;
uint4 flags;
bool reconcile;
int4 highestIndex;
aend = space->wrapOffset(a->start+a->size);
bend = space->wrapOffset(b->start+b->size);
MapRange::RangeType rangeType = MapRange::fixed;
highestIndex = -1;
if ((aend==0)||(bend==0))
end = 0;
else
end = (aend > bend) ? aend : bend;
if (a->contain(b)) { // Does one range contain the other
reconcile = a->reconcile(b); // Can the data-type layout be reconciled
if (a->preferred(b,reconcile)) { // If a's data-type is preferred over b
restype = a->type;
flags = a->flags;
rangeType = a->rangeType;
highestIndex = a->highind;
}
else {
restype = b->type;
flags = b->flags;
rangeType = b->rangeType;
highestIndex = b->highind;
}
if ((a->start==b->start)&&(a->size==b->size)) {
rangeType = (a->rangeType==MapRange::open || b->rangeType==MapRange::open) ? MapRange::open : MapRange::fixed;
if (rangeType == MapRange::open)
highestIndex = (a->highind < b->highind) ? b->highind : a->highind;
}
if (warning && (!reconcile)) { // See if two types match up
if ((b->rangeType != MapRange::open)&&(a->rangeType != MapRange::open))
overlapProblems = true;
}
}
else {
reconcile = false;
restype = (Datatype *)0; // Unable to resolve the type
flags = 0;
}
// Check for really problematic cases
if (!reconcile) {
if ((b->flags & Varnode::typelock)!=0) {
if ((a->flags & Varnode::typelock)!=0)
throw LowlevelError("Overlapping forced variable types : " + a->type->getName() + " " + b->type->getName());
}
}
if (restype == (Datatype *)0) // If all else fails
restype = glb->types->getBase(1,TYPE_UNKNOWN); // Do unknown array (size 1)
a->type = restype;
a->flags = flags;
a->rangeType = rangeType;
a->highind = highestIndex;
if ((!reconcile)&&(a->start != b->start)) { // Truncation is forced
if ((a->flags & Varnode::typelock)!=0) { // If a is locked
return; // Discard b entirely in favor of a
}
// Concede confusion about types, set unknown type rather than a or b's type
a->size = space->wrapOffset(end-a->start);
a->type = glb->types->getBase(a->size,TYPE_UNKNOWN);
a->flags = 0;
a->rangeType = MapRange::fixed;
a->highind = -1;
return;
}
a->size = restype->getSize();
}
/// MapRange hints from the given collection are merged into a definitive set of Symbols
/// for \b this scope. Overlapping or open MapRange hints are adjusted to form a disjoint
/// cover of the mapped portion of the address space. Names for the disjoint cover elements /// cover of the mapped portion of the address space. Names for the disjoint cover elements
/// are chosen, and these form the final Symbols. /// are chosen, and these form the final Symbols.
/// \param state is the given collection of MapRange hints /// \param state is the given collection of RangeHints
/// \param warning is \b true if a warning comment should be generated for overlaps that cannot be reconciled /// \return \b true if there were overlaps that could not be reconciled
void ScopeLocal::restructure(MapState &state,bool warning) bool ScopeLocal::restructure(MapState &state)
{ {
MapRange cur; RangeHint cur;
MapRange *next; RangeHint *next;
// This implementation does not allow a range // This implementation does not allow a range
// to contain both ~0 and 0 // to contain both ~0 and 0
overlapProblems = false; bool overlapProblems = false;
if (!state.initialize()) return; // No references to stack at all if (!state.initialize())
return overlapProblems; // No references to stack at all
cur = *state.next(); cur = *state.next();
while(state.getNext()) { while(state.getNext()) {
next = state.next(); next = state.next();
if (next->sstart < cur.sstart+cur.size) // Do the ranges intersect if (next->sstart < cur.sstart+cur.size) { // Do the ranges intersect
rangeUnion(&cur,next,warning); // Union them if (cur.merge(next,space,glb->types)) // Union them
overlapProblems = true;
}
else { else {
if (!rangeAbsorb(&cur,next)) { if (!cur.absorb(next)) {
if (cur.rangeType == MapRange::open) if (cur.rangeType == RangeHint::open)
cur.size = next->sstart-cur.sstart; cur.size = next->sstart-cur.sstart;
if (adjustFit(cur)) if (adjustFit(cur))
createEntry(cur); createEntry(cur);
@ -1030,6 +1034,7 @@ void ScopeLocal::restructure(MapState &state,bool warning)
} }
// The last range is artificial so we don't // The last range is artificial so we don't
// build an entry for it // build an entry for it
return overlapProblems;
} }
/// Given a set of alias starting offsets, calculate whether each Symbol within this scope might be /// Given a set of alias starting offsets, calculate whether each Symbol within this scope might be

View file

@ -46,13 +46,16 @@ public:
/// starting at a specific address offset (typically on the stack). It describes /// starting at a specific address offset (typically on the stack). It describes
/// where the data-type starts, what data-type it might be, and how far it extends /// where the data-type starts, what data-type it might be, and how far it extends
/// from the start point (possibly as an array). /// from the start point (possibly as an array).
struct MapRange { class RangeHint {
friend class ScopeLocal;
public:
/// \brief The basic categorization of the range /// \brief The basic categorization of the range
enum RangeType { enum RangeType {
fixed = 0, ///< A data-type with a fixed size fixed = 0, ///< A data-type with a fixed size
open = 1, ///< An array with a (possibly unknown) number of elements open = 1, ///< An array with a (possibly unknown) number of elements
endpoint = 2 ///< An (artificial) boundary to the range of bytes getting analyzed endpoint = 2 ///< An (artificial) boundary to the range of bytes getting analyzed
}; };
private:
uintb start; ///< Starting offset of \b this range of bytes uintb start; ///< Starting offset of \b this range of bytes
int4 size; ///< Number of bytes in a single element of this range int4 size; ///< Number of bytes in a single element of this range
intb sstart; ///< A signed version of the starting offset intb sstart; ///< A signed version of the starting offset
@ -60,12 +63,16 @@ struct MapRange {
uint4 flags; ///< Additional boolean properties of this range uint4 flags; ///< Additional boolean properties of this range
RangeType rangeType; ///< The type of range RangeType rangeType; ///< The type of range
int4 highind; ///< Minimum upper bound on the array index (if \b this is \e open) int4 highind; ///< Minimum upper bound on the array index (if \b this is \e open)
MapRange(void) {} ///< Uninitialized constructor public:
MapRange(uintb st,int4 sz,intb sst,Datatype *ct,uint4 fl,RangeType rt,int4 hi) { RangeHint(void) {} ///< Uninitialized constructor
RangeHint(uintb st,int4 sz,intb sst,Datatype *ct,uint4 fl,RangeType rt,int4 hi) {
start=st; size=sz; sstart=sst; type=ct; flags=fl; rangeType = rt; highind=hi; } ///< Initialized constructor start=st; size=sz; sstart=sst; type=ct; flags=fl; rangeType = rt; highind=hi; } ///< Initialized constructor
bool reconcile(const MapRange *b) const; bool reconcile(const RangeHint *b) const;
bool contain(const MapRange *b) const; bool contain(const RangeHint *b) const;
bool preferred(const MapRange *b,bool reconcile) const; bool preferred(const RangeHint *b,bool reconcile) const;
bool absorb(RangeHint *b); ///< Try to absorb the other RangeHint into \b this
bool merge(RangeHint *b,AddrSpace *space,TypeFactory *typeFactory); ///< Try to form the union of \b this with another RangeHint
static bool compareRanges(const RangeHint *a,const RangeHint *b); ///< Compare to RangeHint pointers
}; };
class ProtoModel; class ProtoModel;
@ -108,19 +115,18 @@ public:
/// \brief A container for hints about the data-type layout of an address space /// \brief A container for hints about the data-type layout of an address space
/// ///
/// A collection of data-type hints for the address space (as MapRange objects) can /// A collection of data-type hints for the address space (as RangeHint objects) can
/// be collected from Varnodes, HighVariables or other sources, using the /// be collected from Varnodes, HighVariables or other sources, using the
/// gatherVarnodes(), gatherHighs(), and gatherOpen() methods. This class can then sort /// gatherVarnodes(), gatherHighs(), and gatherOpen() methods. This class can then sort
/// and iterate through the MapRange objects. /// and iterate through the RangeHint objects.
class MapState { class MapState {
AddrSpace *spaceid; ///< The address space being analyzed AddrSpace *spaceid; ///< The address space being analyzed
RangeList range; ///< The subset of ranges, within the whole address space to analyze RangeList range; ///< The subset of ranges, within the whole address space to analyze
vector<MapRange *> maplist; ///< The list of collected MapRange hints vector<RangeHint *> maplist; ///< The list of collected RangeHints
vector<MapRange *>::iterator iter; ///< The current iterator into the MapRange hints vector<RangeHint *>::iterator iter; ///< The current iterator into the RangeHints
Datatype *defaultType; ///< The default data-type to use for MapRanges Datatype *defaultType; ///< The default data-type to use for RangeHints
AliasChecker checker; ///< A collection of pointer Varnodes into our address space AliasChecker checker; ///< A collection of pointer Varnodes into our address space
void addRange(uintb st,Datatype *ct,uint4 fl,MapRange::RangeType rt,int4 hi); ///< Add a hint to the collection void addRange(uintb st,Datatype *ct,uint4 fl,RangeHint::RangeType rt,int4 hi); ///< Add a hint to the collection
static bool compareRanges(const MapRange *a,const MapRange *b); ///< Compare to MapRange pointers
public: public:
#ifdef OPACTION_DEBUG #ifdef OPACTION_DEBUG
mutable bool debugon; mutable bool debugon;
@ -137,7 +143,7 @@ public:
void gatherVarnodes(const Funcdata &fd); ///< Add stack Varnodes as hints to the collection void gatherVarnodes(const Funcdata &fd); ///< Add stack Varnodes as hints to the collection
void gatherHighs(const Funcdata &fd); ///< Add HighVariables as hints to the collection void gatherHighs(const Funcdata &fd); ///< Add HighVariables as hints to the collection
void gatherOpen(const Funcdata &fd); ///< Add pointer references as hints to the collection void gatherOpen(const Funcdata &fd); ///< Add pointer references as hints to the collection
MapRange *next(void) { return *iter; } ///< Get the current MapRange hint in the collection RangeHint *next(void) { return *iter; } ///< Get the current RangeHint in the collection
bool getNext(void) { ++iter; if (iter==maplist.end()) return false; return true; } ///< Advance the iterator, return \b true if another hint is available bool getNext(void) { ++iter; if (iter==maplist.end()) return false; return true; } ///< Advance the iterator, return \b true if another hint is available
}; };
@ -153,13 +159,10 @@ class ScopeLocal : public ScopeInternal {
RangeList localRange; ///< The set of addresses that might hold mapped locals (not parameters) RangeList localRange; ///< The set of addresses that might hold mapped locals (not parameters)
map<AddressUsePointPair,string> nameRecommend; ///< Symbol name recommendations for specific addresses map<AddressUsePointPair,string> nameRecommend; ///< Symbol name recommendations for specific addresses
bool stackGrowsNegative; ///< Marked \b true if the stack is considered to \e grow towards smaller offsets bool stackGrowsNegative; ///< Marked \b true if the stack is considered to \e grow towards smaller offsets
bool overlapProblems; ///< Cached problem flag
bool rangeLocked; ///< True if the subset of addresses \e mapped to \b this scope has been locked bool rangeLocked; ///< True if the subset of addresses \e mapped to \b this scope has been locked
bool adjustFit(MapRange &a) const; ///< Make the given MapRange fit in the current Symbol map bool adjustFit(RangeHint &a) const; ///< Make the given RangeHint fit in the current Symbol map
void createEntry(const MapRange &a); ///< Create a Symbol entry corresponding to the given (fitted) MapRange void createEntry(const RangeHint &a); ///< Create a Symbol entry corresponding to the given (fitted) RangeHint
bool rangeAbsorb(MapRange *a,MapRange *b); ///< Try to absorb the second MapRange into the first bool restructure(MapState &state); ///< Merge hints into a formal Symbol layout of the address space
void rangeUnion(MapRange *a,MapRange *b,bool warning); ///< Try to form the union of the given two MapRanges
void restructure(MapState &state,bool warning); ///< 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 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 fakeInputSymbols(void); ///< Make sure all stack inputs have an associated Symbol
void collectNameRecs(void); ///< Collect names of unlocked Symbols on the stack void collectNameRecs(void); ///< Collect names of unlocked Symbols on the stack