Simpler LanedRegister collection scheme

This commit is contained in:
caheckman 2019-11-17 14:12:23 -05:00
parent dddcf4c715
commit 93471fb3ea
9 changed files with 136 additions and 243 deletions

View file

@ -220,6 +220,42 @@ AddrSpace *Architecture::getSpaceBySpacebase(const Address &loc,int4 size) const
return (AddrSpace *)0; return (AddrSpace *)0;
} }
/// Look-up the laned register record associated with a specific storage location. Currently, the
/// record is only associated with the \e size of the storage, not its address. If there is no
/// associated record, null is returned.
/// \param loc is the starting address of the storage location
/// \param size is the size of the storage in bytes
/// \return the matching LanedRegister record or null
const LanedRegister *Architecture::getLanedRegister(const Address &loc,int4 size) const
{
int4 min = 0;
int4 max = lanerecords.size() - 1;
while(min <= max) {
int4 mid = (min + max) / 2;
int4 sz = lanerecords[mid].getWholeSize();
if (sz < size)
min = mid + 1;
else if (size < sz)
max = mid - 1;
else
return &lanerecords[mid];
}
return (const LanedRegister *)0;
}
/// Return a size intended for comparison with a Varnode size to immediately determine if
/// the Varnode is a potential laned register. If there are no laned registers for the architecture,
/// -1 is returned.
/// \return the size in bytes of the smallest laned register or -1.
int4 Architecture::getMinimumLanedRegisterSize(void) const
{
if (lanerecords.empty())
return -1;
return lanerecords[0].getWholeSize();
}
/// The default model is used whenever an explicit model is not known /// The default model is used whenever an explicit model is not known
/// or can't be determined. /// or can't be determined.
/// \param nm is the name of the model to set /// \param nm is the name of the model to set
@ -817,32 +853,23 @@ void Architecture::parseIncidentalCopy(const Element *el)
void Architecture::parseLaneSizes(const Element *el) void Architecture::parseLaneSizes(const Element *el)
{ {
vector<uint4> maskList;
const List &childList(el->getChildren()); const List &childList(el->getChildren());
List::const_iterator iter; List::const_iterator iter;
LanedRegister lanedRegister; // Only allocate once LanedRegister lanedRegister; // Only allocate once
for(iter=childList.begin();iter!=childList.end();++iter) { for(iter=childList.begin();iter!=childList.end();++iter) {
if (lanedRegister.restoreXml(*iter, this)) { if (lanedRegister.restoreXml(*iter, this)) {
lanerecords.push_back(lanedRegister); int4 sizeIndex = lanedRegister.getWholeSize();
while (maskList.size() <= sizeIndex)
maskList.push_back(0);
maskList[sizeIndex] |= lanedRegister.getSizeBitMask();
} }
} }
if (lanerecords.empty()) return; lanerecords.clear();
lanerecords.sort(); for(int4 i=0;i<maskList.size();++i) {
if (maskList[i] == 0) continue;
// Dedup records that are contained by (the following) records lanerecords.push_back(LanedRegister(i,maskList[i]));
list<LanedRegister>::iterator viter = lanerecords.begin();
list<LanedRegister>::iterator nextiter = viter;
++nextiter;
while(nextiter != lanerecords.end()) {
if ((*viter).contains(*nextiter)) {
lanerecords.erase(nextiter);
nextiter = viter;
++nextiter;
}
else {
++viter;
++nextiter;
}
} }
} }

View file

@ -152,7 +152,7 @@ public:
vector<TypeOp *> inst; ///< Registered p-code instructions vector<TypeOp *> inst; ///< Registered p-code instructions
UserOpManage userops; ///< Specifically registered user-defined p-code ops UserOpManage userops; ///< Specifically registered user-defined p-code ops
vector<PreferSplitRecord> splitrecords; ///< registers that we would prefer to see split for this processor vector<PreferSplitRecord> splitrecords; ///< registers that we would prefer to see split for this processor
list<LanedRegister> lanerecords; ///< Vector registers that have preferred lane sizes vector<LanedRegister> lanerecords; ///< Vector registers that have preferred lane sizes
ActionDatabase allacts; ///< Actions that can be applied in this architecture ActionDatabase allacts; ///< Actions that can be applied in this architecture
bool loadersymbols_parsed; ///< True if loader symbols have been read bool loadersymbols_parsed; ///< True if loader symbols have been read
#ifdef CPUI_STATISTICS #ifdef CPUI_STATISTICS
@ -167,6 +167,8 @@ public:
bool hasModel(const string &nm) const; ///< Does this Architecture have a specific PrototypeModel bool hasModel(const string &nm) const; ///< Does this Architecture have a specific PrototypeModel
bool highPtrPossible(const Address &loc,int4 size) const; ///< Are pointers possible to the given location? bool highPtrPossible(const Address &loc,int4 size) const; ///< Are pointers possible to the given location?
AddrSpace *getSpaceBySpacebase(const Address &loc,int4 size) const; ///< Get space associated with a \e spacebase register AddrSpace *getSpaceBySpacebase(const Address &loc,int4 size) const; ///< Get space associated with a \e spacebase register
const LanedRegister *getLanedRegister(const Address &loc,int4 size) const; ///< Get LanedRegister associated with storage
int4 getMinimumLanedRegisterSize(void) const; ///< Get the minimum size of a laned register in bytes
void setDefaultModel(const string &nm); ///< Set the default PrototypeModel void setDefaultModel(const string &nm); ///< Set the default PrototypeModel
void clearAnalysis(Funcdata *fd); ///< Clear analysis specific to a function void clearAnalysis(Funcdata *fd); ///< Clear analysis specific to a function
void readLoaderSymbols(void); ///< Read any symbols from loader into database void readLoaderSymbols(void); ///< Read any symbols from loader into database

View file

@ -495,127 +495,6 @@ int4 ActionStackPtrFlow::apply(Funcdata &data)
return 0; return 0;
} }
/// Mark every PcodeOp that is reachable from the given Varnode and create a LanedAccess record.
/// \param data is the function to trace through
/// \param base is the description of the laned register being traced from
/// \param vn is the Varnode to trace
/// \param pos is the significance position of the Varnode within the laned register
void ActionCollectLanedAccess::traceVarnode(Funcdata &data,const LanedRegister *base,Varnode *vn,int4 pos)
{
list<PcodeOp *>::const_iterator iter = vn->beginDescend();
int4 step = 0;
while(step < 2) {
PcodeOp *op;
if (step == 0) {
op = *iter;
++iter;
if (iter == vn->endDescend())
step = 1;
}
else {
step = 2;
if (!vn->isWritten()) continue;
op = vn->getDef();
}
if (op->isMark()) continue;
// Make sure op is associated with a lane access records describing its biggest Varnode
switch(op->code()) {
case CPUI_LOAD:
case CPUI_PIECE:
case CPUI_INT_ZEXT:
case CPUI_INT_SEXT:
if (vn != op->getOut()) continue; // Biggest Varnode is the output
break;
case CPUI_SUBPIECE:
if (vn != op->getIn(0)) continue; // Biggest Varnode is first input
break;
case CPUI_STORE:
if (vn != op->getIn(2)) continue;
break;
default:
break;
}
op->setMark();
data.opMarkLanedAccess(base, op, vn->getSize(), pos);
}
}
/// \brief Search for Varnodes that match the given laned vector register
///
/// All varnodes (bigger than 8 bytes) that are contained in the vector register are processed,
/// looking for a working lane scheme. Data-flow from these Varnodes is traces and LanedAccess
/// records are created for each PcodeOp flowed through.
/// \param data is the function being traced
/// \param lanedRegister is the given register and acceptable lane schemes
/// \param iter is an iterator to the first Varnode that matches the vector register
void ActionCollectLanedAccess::processLane(Funcdata &data,const LanedRegister &lanedRegister,
VarnodeLocSet::const_iterator iter)
{
int4 fullSize = lanedRegister.getStorage().size;
Address startAddress(lanedRegister.getStorage().getAddr());
Address lastAddress(startAddress + (fullSize-1));
VarnodeLocSet::const_iterator enditer = data.endLoc();
while(iter != enditer) {
Varnode *vn = *iter;
++iter;
if (lastAddress < vn->getAddr())
break;
if (vn->getSize() <= 8) // Varnode not big enough to be vector register
continue;
int4 diff = (int4)(vn->getOffset() - startAddress.getOffset());
if (diff + vn->getSize() > fullSize) // Must be contained by full register
continue;
if (vn->getSpace()->isBigEndian())
diff = fullSize - (diff + vn->getSize());
traceVarnode(data, &lanedRegister, vn, diff);
}
}
/// Give each PcodeOp in the laned access list a chance to propagate to new PcodeOps,
/// which will have new records added to the list.
/// \param data is the function being traced
void ActionCollectLanedAccess::propagate(Funcdata &data)
{
list<LanedAccess>::const_iterator iter = data.beginLaneAccess();
while(iter != data.endLaneAccess()) {
const LanedAccess lanedAccess( *iter );
PcodeOp *op = lanedAccess.getOp();
int4 sz = lanedAccess.getSize();
for(int4 i=0;i<op->numInput();++i) {
Varnode *vn = op->getIn(i);
if (vn->getSize() != sz) continue; // Size must match exactly
if (vn->isConstant() || vn->isAnnotation()) continue;
traceVarnode(data, lanedAccess.getBase(), vn, lanedAccess.getBytePos());
}
++iter;
}
}
int4 ActionCollectLanedAccess::apply(Funcdata &data)
{
if (data.getArch()->lanerecords.empty())
return 0;
const LanedRegister &lastRecord( data.getArch()->lanerecords.back() );
Address lastAddress( lastRecord.getStorage().getAddr() + lastRecord.getStorage().size - 1);
list<LanedRegister>::const_iterator iter;
for(iter=data.getArch()->lanerecords.begin();iter!=data.getArch()->lanerecords.end();++iter) {
const LanedRegister &lanedRegister( *iter );
VarnodeLocSet::const_iterator viter = data.beginLoc(lanedRegister.getStorage().getAddr());
if (viter == data.endLoc()) break;
Varnode *vn = *viter;
if (lastAddress < vn->getAddr()) break;
processLane(data,lanedRegister,viter);
}
propagate(data);
list<LanedAccess>::const_iterator aiter;
for(aiter=data.beginLaneAccess();aiter!=data.endLaneAccess();++aiter)
(*aiter).getOp()->clearMark();
return 0;
}
/// \brief Try to divide a single Varnode into lanes /// \brief Try to divide a single Varnode into lanes
/// ///
/// Look for a CPUI_SUBPIECE op that takes the given Varnode as the input or a /// Look for a CPUI_SUBPIECE op that takes the given Varnode as the input or a
@ -626,15 +505,17 @@ int4 ActionCollectLanedAccess::apply(Funcdata &data)
/// \param data is the function being transformed /// \param data is the function being transformed
/// \param vn is the given single Varnode /// \param vn is the given single Varnode
/// \param lanedRegister is acceptable set of lane sizes for the Varnode /// \param lanedRegister is acceptable set of lane sizes for the Varnode
/// \param bytePos is the significance position of the Varnode within the laned register
/// \param allowDowncast is \b true if we allow lane systems with SUBPIECE terminators /// \param allowDowncast is \b true if we allow lane systems with SUBPIECE terminators
bool ActionLaneDivide::processVarnode(Funcdata &data,Varnode *vn,const LanedRegister &lanedRegister,int4 bytePos, /// \return \b true if the Varnode (and its data-flow) was successfully split
bool allowDowncast) bool ActionLaneDivide::processVarnode(Funcdata &data,Varnode *vn,const LanedRegister &lanedRegister,bool allowDowncast)
{ {
list<PcodeOp *>::const_iterator iter = vn->beginDescend(); list<PcodeOp *>::const_iterator iter = vn->beginDescend();
LanedRegister checkedLanes; LanedRegister checkedLanes;
int4 step = 0; // 0 = descendants, 1 = def, 2 = done int4 step = 0; // 0 = descendants, 1 = def, 2 = done
if (iter == vn->endDescend()) {
step = 1;
}
while(step < 2) { while(step < 2) {
int4 curSize; // Putative lane size int4 curSize; // Putative lane size
if (step == 0) { if (step == 0) {
@ -657,10 +538,8 @@ bool ActionLaneDivide::processVarnode(Funcdata &data,Varnode *vn,const LanedRegi
} }
if (lanedRegister.allowedLane(curSize)) { if (lanedRegister.allowedLane(curSize)) {
if (checkedLanes.allowedLane(curSize)) continue; if (checkedLanes.allowedLane(curSize)) continue;
checkedLanes.addSize(curSize); // Only check this scheme once checkedLanes.addLaneSize(curSize); // Only check this scheme once
LaneDescription description(lanedRegister.getStorage().size,curSize); // Lane scheme dictated by curSize LaneDescription description(lanedRegister.getWholeSize(),curSize); // Lane scheme dictated by curSize
if (!description.subset(bytePos,vn->getSize())) // Try to restrict lane scheme to actual Varnode
continue;
LaneDivide laneDivide(&data,vn,description,allowDowncast); LaneDivide laneDivide(&data,vn,description,allowDowncast);
if (laneDivide.doTrace()) { if (laneDivide.doTrace()) {
laneDivide.apply(); laneDivide.apply();
@ -675,31 +554,28 @@ bool ActionLaneDivide::processVarnode(Funcdata &data,Varnode *vn,const LanedRegi
int4 ActionLaneDivide::apply(Funcdata &data) int4 ActionLaneDivide::apply(Funcdata &data)
{ {
list<LanedAccess>::const_iterator iter; map<VarnodeData,const LanedRegister *>::const_iterator iter;
bool allowDowncast = false; bool allowDowncast = false;
for(int4 i=0;i<2;++i) { for(int4 i=0;i<2;++i) {
for(iter=data.beginLaneAccess();iter!=data.endLaneAccess();++iter) { for(iter=data.beginLaneAccess();iter!=data.endLaneAccess();++iter) {
const LanedAccess &lanedAccess(*iter); const LanedRegister *lanedReg = (*iter).second;
PcodeOp *op = lanedAccess.getOp(); Address addr = (*iter).first.getAddr();
if (op->isDead()) continue; int4 sz = (*iter).first.size;
Varnode *vn = op->getOut(); VarnodeLocSet::const_iterator viter = data.beginLoc(sz,addr);
if (vn != (Varnode *)0 && vn->getSize() == lanedAccess.getSize()) VarnodeLocSet::const_iterator venditer = data.endLoc(sz,addr);
processVarnode(data, vn, *lanedAccess.getBase(), lanedAccess.getBytePos(), allowDowncast); while(viter != venditer) {
else { Varnode *vn = *viter;
for(int4 j=0;j<op->numInput();++j) { if (processVarnode(data, vn, *lanedReg, allowDowncast)) {
vn = op->getIn(j); viter = data.beginLoc(sz,addr);
if (vn->getSize() == lanedAccess.getSize()) { venditer = data.endLoc(sz, addr); // Recalculate bounds
if (!vn->isConstant() && !vn->isAnnotation() && !vn->isWritten()) {
processVarnode(data, vn, *lanedAccess.getBase(), lanedAccess.getBytePos(), allowDowncast);
break;
}
}
} }
else
++viter;
} }
} }
allowDowncast = true; allowDowncast = true;
} }
data.clearLanedAccessList(); data.clearLanedAccessMap();
return 0; return 0;
} }
@ -1238,14 +1114,30 @@ int4 ActionDeindirect::apply(Funcdata &data)
return 0; return 0;
} }
/// Check if the given Varnode has a matching LanedRegister record. If so, add its
/// storage location to the given function's laned access list.
/// \param data is the given function
/// \param vn is the given Varnode
void ActionVarnodeProps::markLanedVarnode(Funcdata &data,Varnode *vn)
{
if (vn->isConstant()) return;
Architecture *glb = data.getArch();
const LanedRegister *lanedRegister = glb->getLanedRegister(vn->getAddr(),vn->getSize());
if (lanedRegister != (const LanedRegister *)0)
data.markLanedVarnode(vn,lanedRegister);
}
int4 ActionVarnodeProps::apply(Funcdata &data) int4 ActionVarnodeProps::apply(Funcdata &data)
{ {
Architecture *glb = data.getArch(); Architecture *glb = data.getArch();
bool cachereadonly = glb->readonlypropagate; bool cachereadonly = glb->readonlypropagate;
if (glb->userops.getVolatileRead() == (VolatileReadOp *)0) { int4 minLanedSize = 1000000; // Default size meant to filter no Varnodes
if (!cachereadonly) if (!data.isLanedRegComplete()) {
return 0; // Nothing to do to special properties int4 sz = glb->getMinimumLanedRegisterSize();
if (sz > 0)
minLanedSize = sz;
} }
VarnodeLocSet::const_iterator iter; VarnodeLocSet::const_iterator iter;
Varnode *vn; Varnode *vn;
@ -1254,6 +1146,9 @@ int4 ActionVarnodeProps::apply(Funcdata &data)
while(iter != data.endLoc()) { while(iter != data.endLoc()) {
vn = *iter++; // Advance iterator in case vn is deleted vn = *iter++; // Advance iterator in case vn is deleted
if (vn->isAnnotation()) continue; if (vn->isAnnotation()) continue;
int4 vnSize = vn->getSize();
if (vnSize >= minLanedSize)
markLanedVarnode(data, vn);
if (vn->hasActionProperty()) { if (vn->hasActionProperty()) {
if (cachereadonly&&vn->isReadOnly()) { if (cachereadonly&&vn->isReadOnly()) {
if (data.fillinReadOnly(vn)) // Try to replace vn with its lookup in LoadImage if (data.fillinReadOnly(vn)) // Try to replace vn with its lookup in LoadImage
@ -1263,7 +1158,7 @@ int4 ActionVarnodeProps::apply(Funcdata &data)
if (data.replaceVolatile(vn)) if (data.replaceVolatile(vn))
count += 1; // Try to replace vn with pcode op count += 1; // Try to replace vn with pcode op
} }
else if (((vn->getNZMask() & vn->getConsume())==0)&&(vn->getSize()<=sizeof(uintb))) { else if (((vn->getNZMask() & vn->getConsume())==0)&&(vnSize<=sizeof(uintb))) {
// FIXME: uintb should be arbitrary precision // FIXME: uintb should be arbitrary precision
if (vn->isConstant()) continue; // Don't replace a constant if (vn->isConstant()) continue; // Don't replace a constant
if (vn->isWritten()) { if (vn->isWritten()) {
@ -1283,6 +1178,7 @@ int4 ActionVarnodeProps::apply(Funcdata &data)
} }
} }
} }
data.setLanedRegGenerated();
return 0; return 0;
} }
@ -4714,7 +4610,6 @@ void universal_action(Architecture *conf)
// actmainloop->addAction( new ActionParamShiftStop("paramshift") ); // actmainloop->addAction( new ActionParamShiftStop("paramshift") );
actmainloop->addAction( new ActionRestrictLocal("localrecovery") ); // Do before dead code removed actmainloop->addAction( new ActionRestrictLocal("localrecovery") ); // Do before dead code removed
actmainloop->addAction( new ActionDeadCode("deadcode") ); actmainloop->addAction( new ActionDeadCode("deadcode") );
actmainloop->addAction( new ActionCollectLanedAccess("base") );
actmainloop->addAction( new ActionDynamicMapping("dynamic") ); // Must come before restructurevarnode and infertypes actmainloop->addAction( new ActionDynamicMapping("dynamic") ); // Must come before restructurevarnode and infertypes
actmainloop->addAction( new ActionRestructureVarnode("localrecovery") ); actmainloop->addAction( new ActionRestructureVarnode("localrecovery") );
actmainloop->addAction( new ActionSpacebase("base") ); // Must come before infertypes and nonzeromask actmainloop->addAction( new ActionSpacebase("base") ); // Must come before infertypes and nonzeromask

View file

@ -97,26 +97,6 @@ public:
virtual int4 apply(Funcdata &data); virtual int4 apply(Funcdata &data);
}; };
/// \brief Find PcodeOps that are accessing values from laned registers
///
/// This looks for Varnodes that match any of the LanedRegister records associated with
/// the architecture. A record is created in the function's LanedAccess list for every
/// PcodeOp that accesses one of these Varnodes. These are later examined by ActionLaneDivide.
/// The LanedRegister is the key for finding the Varnode, but the \e big property can propagate
/// through data-flow to other Varnodes that are not necessarily using the same storage (i.e. uniques).
class ActionCollectLanedAccess : public Action {
void traceVarnode(Funcdata &data,const LanedRegister *base,Varnode *vn,int4 pos); ///< Trace a big Varnode instance to other big Varnodes
void processLane(Funcdata &data,const LanedRegister &lanedRegister,VarnodeLocSet::const_iterator iter);
void propagate(Funcdata &data); ///< Discover other PcodeOps that use laned values
public:
ActionCollectLanedAccess(const string &g) : Action(rule_onceperfunc,"collectlanedaccess",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionCollectLanedAccess(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Find Varnodes with a vectorized lane scheme and attempt to split the lanes /// \brief Find Varnodes with a vectorized lane scheme and attempt to split the lanes
/// ///
/// The Architecture lists (vector) registers that may be used to perform parallelized operations /// The Architecture lists (vector) registers that may be used to perform parallelized operations
@ -124,7 +104,7 @@ public:
/// if a particular lane scheme makes sense in terms of the function's data-flow, and then /// if a particular lane scheme makes sense in terms of the function's data-flow, and then
/// rewrites the data-flow so that the lanes become explicit Varnodes. /// rewrites the data-flow so that the lanes become explicit Varnodes.
class ActionLaneDivide : public Action { class ActionLaneDivide : public Action {
bool processVarnode(Funcdata &data,Varnode *vn,const LanedRegister &lanedRegister,int4 bytePos,bool allowDowncast); bool processVarnode(Funcdata &data,Varnode *vn,const LanedRegister &lanedRegister,bool allowDowncast);
public: public:
ActionLaneDivide(const string &g) : Action(rule_onceperfunc,"lanedivide",g) {} ///< Constructor ActionLaneDivide(const string &g) : Action(rule_onceperfunc,"lanedivide",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const { virtual Action *clone(const ActionGroupList &grouplist) const {
@ -222,8 +202,15 @@ public:
virtual int4 apply(Funcdata &data); virtual int4 apply(Funcdata &data);
}; };
/// \brief Transform read-only variables to constants /// \brief Transform based on Varnode properties, such as \e read-only and \e volatile
///
/// This performs various transforms that are based on Varnode properties.
/// - Read-only Varnodes are converted to the underlying constant
/// - Volatile Varnodes are converted read/write functions
/// - Varnodes whose values are not consumed are replaced with constant 0 Varnodes
/// - Large Varnodes are flagged for lane analysis
class ActionVarnodeProps : public Action { class ActionVarnodeProps : public Action {
void markLanedVarnode(Funcdata &data,Varnode *vn); ///< Mark possible laned register storage
public: public:
ActionVarnodeProps(const string &g) : Action(0,"varnodeprops",g) {} ///< Constructor ActionVarnodeProps(const string &g) : Action(0,"varnodeprops",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const { virtual Action *clone(const ActionGroupList &grouplist) const {

View file

@ -56,7 +56,8 @@ class Funcdata {
restart_pending = 0x200, ///< Analysis must be restarted (because of new override info) restart_pending = 0x200, ///< Analysis must be restarted (because of new override info)
unimplemented_present = 0x400, ///< Set if function contains unimplemented instructions unimplemented_present = 0x400, ///< Set if function contains unimplemented instructions
baddata_present = 0x800, ///< Set if function flowed into bad data baddata_present = 0x800, ///< Set if function flowed into bad data
double_precis_on = 0x1000 ///< Set if we are performing double precision recovery double_precis_on = 0x1000, ///< Set if we are performing double precision recovery
big_varnodes_generated = 0x2000 ///< Set when search for laned registers is complete
}; };
uint4 flags; ///< Boolean properties associated with \b this function uint4 flags; ///< Boolean properties associated with \b this function
uint4 clean_up_index; ///< Creation index of first Varnode created after start of cleanup uint4 clean_up_index; ///< Creation index of first Varnode created after start of cleanup
@ -80,7 +81,7 @@ class Funcdata {
Merge covermerge; ///< Variable range intersection algorithms Merge covermerge; ///< Variable range intersection algorithms
ParamActive *activeoutput; ///< Data for assessing which parameters are passed to \b this function ParamActive *activeoutput; ///< Data for assessing which parameters are passed to \b this function
Override localoverride; ///< Overrides of data-flow, prototypes, etc. that are local to \b this function Override localoverride; ///< Overrides of data-flow, prototypes, etc. that are local to \b this function
list<LanedAccess> lanedList; ///< List of ops that are accessing potentially laned registers map<VarnodeData,const LanedRegister *> lanedMap; ///< Current storage locations which may be laned registers
// Low level Varnode functions // Low level Varnode functions
void setVarnodeProperties(Varnode *vn) const; ///< Look-up boolean properties and data-type information void setVarnodeProperties(Varnode *vn) const; ///< Look-up boolean properties and data-type information
@ -131,6 +132,8 @@ public:
bool isTypeRecoveryOn(void) const { return ((flags&typerecovery_on)!=0); } ///< Has data-type recovery processes started bool isTypeRecoveryOn(void) const { return ((flags&typerecovery_on)!=0); } ///< Has data-type recovery processes started
bool hasNoCode(void) const { return ((flags & no_code)!=0); } ///< Return \b true if \b this function has no code body bool hasNoCode(void) const { return ((flags & no_code)!=0); } ///< Return \b true if \b this function has no code body
void setNoCode(bool val) { if (val) flags |= no_code; else flags &= ~no_code; } ///< Toggle whether \b this has a body void setNoCode(bool val) { if (val) flags |= no_code; else flags &= ~no_code; } ///< Toggle whether \b this has a body
bool isLanedRegComplete(void) const { return ((flags&big_varnodes_generated)!=0); } ///< Have potential laned registers been generated
void setLanedRegGenerated(void) { flags |= big_varnodes_generated; } ///< Mark that laned registers have been collected
/// \brief Toggle whether \b this is being used for jump-table recovery /// \brief Toggle whether \b this is being used for jump-table recovery
/// ///
@ -347,6 +350,11 @@ public:
/// \brief End of (input or free) Varnodes at a given storage address /// \brief End of (input or free) Varnodes at a given storage address
VarnodeDefSet::const_iterator endDef(uint4 fl,const Address &addr) const { return vbank.endDef(fl,addr); } VarnodeDefSet::const_iterator endDef(uint4 fl,const Address &addr) const { return vbank.endDef(fl,addr); }
void markLanedVarnode(Varnode *vn,const LanedRegister *lanedReg); ///< Mark Varnode as potential laned register
map<VarnodeData,const LanedRegister *>::const_iterator beginLaneAccess(void) const { return lanedMap.begin(); } ///< Beginning iterator over laned accesses
map<VarnodeData,const LanedRegister *>::const_iterator endLaneAccess(void) const { return lanedMap.end(); } ///< Ending iterator over laned accesses
void clearLanedAccessMap(void) { lanedMap.clear(); } ///< Clear records from the laned access list
HighVariable *findHigh(const string &name) const; ///< Find a high-level variable by name HighVariable *findHigh(const string &name) const; ///< Find a high-level variable by name
void mapGlobals(void); ///< Make sure there is a Symbol entry for all global Varnodes void mapGlobals(void); ///< Make sure there is a Symbol entry for all global Varnodes
bool checkCallDoubleUse(const PcodeOp *opmatch,const PcodeOp *op,const Varnode *vn,const ParamTrial &trial) const; bool checkCallDoubleUse(const PcodeOp *opmatch,const PcodeOp *op,const Varnode *vn,const ParamTrial &trial) const;
@ -429,10 +437,6 @@ public:
Varnode *opStackLoad(AddrSpace *spc,uintb off,uint4 sz,PcodeOp *op,Varnode *stackptr,bool insertafter); Varnode *opStackLoad(AddrSpace *spc,uintb off,uint4 sz,PcodeOp *op,Varnode *stackptr,bool insertafter);
PcodeOp *opStackStore(AddrSpace *spc,uintb off,PcodeOp *op,bool insertafter); PcodeOp *opStackStore(AddrSpace *spc,uintb off,PcodeOp *op,bool insertafter);
void opUndoPtradd(PcodeOp *op,bool finalize); ///< Convert a CPUI_PTRADD back into a CPUI_INT_ADD void opUndoPtradd(PcodeOp *op,bool finalize); ///< Convert a CPUI_PTRADD back into a CPUI_INT_ADD
void opMarkLanedAccess(const LanedRegister *base,PcodeOp *op,int4 sz,int4 pos); ///< Mark op as using laned register
list<LanedAccess>::const_iterator beginLaneAccess(void) const { return lanedList.begin(); } ///< Beginning iterator over laned accesses
list<LanedAccess>::const_iterator endLaneAccess(void) const { return lanedList.end(); } ///< Ending iterator over laned accesses
void clearLanedAccessList(void) { lanedList.clear(); } ///< Clear records from the laned access list
/// \brief Start of PcodeOp objects with the given op-code /// \brief Start of PcodeOp objects with the given op-code
list<PcodeOp *>::const_iterator beginOp(OpCode opc) const { return obank.begin(opc); } list<PcodeOp *>::const_iterator beginOp(OpCode opc) const { return obank.begin(opc); }

View file

@ -557,19 +557,6 @@ void Funcdata::opUndoPtradd(PcodeOp *op,bool finalize)
opInsertBefore(multOp,op); opInsertBefore(multOp,op);
} }
/// Store a record indicating a potential use of a large laned register. Generally, the output
/// of the op is the use, except in the case of SUBPIECE or STORE, where getIn(0) and getIn(2)
/// respectively are the Varnodes being used.
/// \param base is the description of the laned register that is triggering this record
/// \param op is the PcodeOp using the large Varnode
/// \param sz is the size of the large Varnode in bytes
/// \param pos is the significance position of the Varnode, relative to the LanedRegister description
void Funcdata::opMarkLanedAccess(const LanedRegister *base,PcodeOp *op,int4 sz,int4 pos)
{
lanedList.push_back(LanedAccess(base,op,sz,pos));
}
/// Make a clone of the given PcodeOp, copying control-flow properties as well. The data-type /// Make a clone of the given PcodeOp, copying control-flow properties as well. The data-type
/// is \e not cloned. /// is \e not cloned.
/// \param op is the PcodeOp to clone /// \param op is the PcodeOp to clone

View file

@ -286,6 +286,21 @@ void Funcdata::destroyVarnode(Varnode *vn)
vbank.destroy(vn); vbank.destroy(vn);
} }
/// Record the given Varnode as a potential laned register access.
/// The address and size of the Varnode is recorded, anticipating that new
/// Varnodes at the same storage location may be created
/// \param vn is the given Varnode to mark
/// \param lanedReg is the laned register record to associate with the Varnode
void Funcdata::markLanedVarnode(Varnode *vn,const LanedRegister *lanedReg)
{
VarnodeData storage;
storage.space = vn->getSpace();
storage.offset = vn->getOffset();
storage.size = vn->getSize();
lanedMap[storage] = lanedReg;
}
/// Look up the Symbol visible in \b this function's Scope and return the HighVariable /// Look up the Symbol visible in \b this function's Scope and return the HighVariable
/// associated with it. If the Symbol doesn't exist or there is no Varnode holding at least /// associated with it. If the Symbol doesn't exist or there is no Varnode holding at least
/// part of the value of the Symbol, NULL is returned. /// part of the value of the Symbol, NULL is returned.

View file

@ -276,8 +276,10 @@ bool LanedRegister::restoreXml(const Element *el,const AddrSpaceManager *manage)
} }
} }
if (laneSizes.empty()) return false; if (laneSizes.empty()) return false;
VarnodeData storage;
storage.space = (AddrSpace *)0; storage.space = (AddrSpace *)0;
storage.restoreXml(el, manage); storage.restoreXml(el, manage);
wholeSize = storage.size;
sizeBitMask = 0; sizeBitMask = 0;
string::size_type pos = 0; string::size_type pos = 0;
while(pos != string::npos) { while(pos != string::npos) {
@ -299,23 +301,11 @@ bool LanedRegister::restoreXml(const Element *el,const AddrSpaceManager *manage)
s >> sz; s >> sz;
if (sz < 0 || sz > 16) if (sz < 0 || sz > 16)
throw LowlevelError("Bad lane size: " + value); throw LowlevelError("Bad lane size: " + value);
addSize(sz); addLaneSize(sz);
} }
return true; return true;
} }
/// In order to return \b true, the storage for \b this must contain the storage for the other
/// LanedRegister, and every lane scheme of the other LanedRegister must also be a lane scheme
/// for \b this.
/// \param op2 is the other LanedRegister to check for containment
/// \return \b true if \b this contains the other register
bool LanedRegister::contains(const LanedRegister &op2) const
{
if (!storage.contains(op2.storage)) return false;
return ((sizeBitMask & op2.sizeBitMask) == op2.sizeBitMask); // Check for containment of lane size sets
}
TransformManager::~TransformManager(void) TransformManager::~TransformManager(void)
{ {

View file

@ -86,30 +86,16 @@ public:
/// \brief Describes a (register) storage location and the ways it might be split into lanes /// \brief Describes a (register) storage location and the ways it might be split into lanes
class LanedRegister { class LanedRegister {
VarnodeData storage; ///< Defining characteristics of the register int4 wholeSize; ///< Size of the whole register
uint4 sizeBitMask; ///< A 1-bit for every permissible lane size uint4 sizeBitMask; ///< A 1-bit for every permissible lane size
public: public:
LanedRegister(void) { sizeBitMask = 0; } ///< Constructor LanedRegister(void) { wholeSize = 0; sizeBitMask = 0; } ///< Constructor for use with restoreXml
LanedRegister(int4 sz,uint4 mask) { wholeSize = sz; sizeBitMask = mask; } ///< Constructor
bool restoreXml(const Element *el,const AddrSpaceManager *manage); ///< Restore object from XML stream bool restoreXml(const Element *el,const AddrSpaceManager *manage); ///< Restore object from XML stream
const VarnodeData &getStorage(void) const { return storage; } ///< Get VarnodeData for storage int4 getWholeSize(void) const { return wholeSize; } ///< Get the size in bytes of the whole laned register
void addSize(int4 size) { sizeBitMask |= ((uint4)1 << size); } ///< Add a new \e size to the allowed list uint4 getSizeBitMask(void) const { return sizeBitMask; } ///< Get the bit mask of possible lane sizes
void addLaneSize(int4 size) { sizeBitMask |= ((uint4)1 << size); } ///< Add a new \e size to the allowed list
bool allowedLane(int4 size) const { return (((sizeBitMask >> size) & 1) != 0); } ///< Is \e size among the allowed lane sizes bool allowedLane(int4 size) const { return (((sizeBitMask >> size) & 1) != 0); } ///< Is \e size among the allowed lane sizes
bool contains(const LanedRegister &op2) const; ///< Does \b this contain the given register and its possible lanes
bool operator<(const LanedRegister &op2) const { return (storage < op2.storage); } ///< Compare based on VarnodeData
};
/// \brief Record describing the access of a large Varnode that can be traced to a LanedRegister
class LanedAccess {
const LanedRegister *base; ///< Base register dictating the lane scheme
PcodeOp *op; ///< Operation using the big register
int4 size; ///< Size of the register in bytes
int4 bytePos; ///< Significance position relative to the laned register
public:
LanedAccess(const LanedRegister *b,PcodeOp *o,int4 sz,int4 pos) { base=b; op=o; size=sz; bytePos=pos; } ///< Constructor
const LanedRegister *getBase(void) const { return base; } ///< Get the base LanedRegister being traced
PcodeOp *getOp(void) const { return op; } ///< Get the PcodeOp using the large Varnode
int4 getSize(void) const { return size; } ///< Get the size of the Varnode being accessed
int4 getBytePos(void) const { return bytePos; } ///< Get the significance position relative to the laned register
}; };
/// \brief Description of logical lanes within a \b big Varnode /// \brief Description of logical lanes within a \b big Varnode