mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 02:09:44 +02:00
Simpler LanedRegister collection scheme
This commit is contained in:
parent
dddcf4c715
commit
93471fb3ea
9 changed files with 136 additions and 243 deletions
|
@ -220,6 +220,42 @@ AddrSpace *Architecture::getSpaceBySpacebase(const Address &loc,int4 size) const
|
|||
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
|
||||
/// or can't be determined.
|
||||
/// \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)
|
||||
|
||||
{
|
||||
vector<uint4> maskList;
|
||||
const List &childList(el->getChildren());
|
||||
List::const_iterator iter;
|
||||
|
||||
LanedRegister lanedRegister; // Only allocate once
|
||||
for(iter=childList.begin();iter!=childList.end();++iter) {
|
||||
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.sort();
|
||||
|
||||
// Dedup records that are contained by (the following) records
|
||||
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;
|
||||
}
|
||||
lanerecords.clear();
|
||||
for(int4 i=0;i<maskList.size();++i) {
|
||||
if (maskList[i] == 0) continue;
|
||||
lanerecords.push_back(LanedRegister(i,maskList[i]));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -152,7 +152,7 @@ public:
|
|||
vector<TypeOp *> inst; ///< Registered p-code instructions
|
||||
UserOpManage userops; ///< Specifically registered user-defined p-code ops
|
||||
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
|
||||
bool loadersymbols_parsed; ///< True if loader symbols have been read
|
||||
#ifdef CPUI_STATISTICS
|
||||
|
@ -167,6 +167,8 @@ public:
|
|||
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?
|
||||
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 clearAnalysis(Funcdata *fd); ///< Clear analysis specific to a function
|
||||
void readLoaderSymbols(void); ///< Read any symbols from loader into database
|
||||
|
|
|
@ -495,127 +495,6 @@ int4 ActionStackPtrFlow::apply(Funcdata &data)
|
|||
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
|
||||
///
|
||||
/// 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 vn is the given single 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
|
||||
bool ActionLaneDivide::processVarnode(Funcdata &data,Varnode *vn,const LanedRegister &lanedRegister,int4 bytePos,
|
||||
bool allowDowncast)
|
||||
/// \return \b true if the Varnode (and its data-flow) was successfully split
|
||||
bool ActionLaneDivide::processVarnode(Funcdata &data,Varnode *vn,const LanedRegister &lanedRegister,bool allowDowncast)
|
||||
|
||||
{
|
||||
list<PcodeOp *>::const_iterator iter = vn->beginDescend();
|
||||
LanedRegister checkedLanes;
|
||||
int4 step = 0; // 0 = descendants, 1 = def, 2 = done
|
||||
if (iter == vn->endDescend()) {
|
||||
step = 1;
|
||||
}
|
||||
while(step < 2) {
|
||||
int4 curSize; // Putative lane size
|
||||
if (step == 0) {
|
||||
|
@ -657,10 +538,8 @@ bool ActionLaneDivide::processVarnode(Funcdata &data,Varnode *vn,const LanedRegi
|
|||
}
|
||||
if (lanedRegister.allowedLane(curSize)) {
|
||||
if (checkedLanes.allowedLane(curSize)) continue;
|
||||
checkedLanes.addSize(curSize); // Only check this scheme once
|
||||
LaneDescription description(lanedRegister.getStorage().size,curSize); // Lane scheme dictated by curSize
|
||||
if (!description.subset(bytePos,vn->getSize())) // Try to restrict lane scheme to actual Varnode
|
||||
continue;
|
||||
checkedLanes.addLaneSize(curSize); // Only check this scheme once
|
||||
LaneDescription description(lanedRegister.getWholeSize(),curSize); // Lane scheme dictated by curSize
|
||||
LaneDivide laneDivide(&data,vn,description,allowDowncast);
|
||||
if (laneDivide.doTrace()) {
|
||||
laneDivide.apply();
|
||||
|
@ -675,31 +554,28 @@ bool ActionLaneDivide::processVarnode(Funcdata &data,Varnode *vn,const LanedRegi
|
|||
int4 ActionLaneDivide::apply(Funcdata &data)
|
||||
|
||||
{
|
||||
list<LanedAccess>::const_iterator iter;
|
||||
map<VarnodeData,const LanedRegister *>::const_iterator iter;
|
||||
bool allowDowncast = false;
|
||||
for(int4 i=0;i<2;++i) {
|
||||
for(iter=data.beginLaneAccess();iter!=data.endLaneAccess();++iter) {
|
||||
const LanedAccess &lanedAccess(*iter);
|
||||
PcodeOp *op = lanedAccess.getOp();
|
||||
if (op->isDead()) continue;
|
||||
Varnode *vn = op->getOut();
|
||||
if (vn != (Varnode *)0 && vn->getSize() == lanedAccess.getSize())
|
||||
processVarnode(data, vn, *lanedAccess.getBase(), lanedAccess.getBytePos(), allowDowncast);
|
||||
else {
|
||||
for(int4 j=0;j<op->numInput();++j) {
|
||||
vn = op->getIn(j);
|
||||
if (vn->getSize() == lanedAccess.getSize()) {
|
||||
if (!vn->isConstant() && !vn->isAnnotation() && !vn->isWritten()) {
|
||||
processVarnode(data, vn, *lanedAccess.getBase(), lanedAccess.getBytePos(), allowDowncast);
|
||||
break;
|
||||
}
|
||||
}
|
||||
const LanedRegister *lanedReg = (*iter).second;
|
||||
Address addr = (*iter).first.getAddr();
|
||||
int4 sz = (*iter).first.size;
|
||||
VarnodeLocSet::const_iterator viter = data.beginLoc(sz,addr);
|
||||
VarnodeLocSet::const_iterator venditer = data.endLoc(sz,addr);
|
||||
while(viter != venditer) {
|
||||
Varnode *vn = *viter;
|
||||
if (processVarnode(data, vn, *lanedReg, allowDowncast)) {
|
||||
viter = data.beginLoc(sz,addr);
|
||||
venditer = data.endLoc(sz, addr); // Recalculate bounds
|
||||
}
|
||||
else
|
||||
++viter;
|
||||
}
|
||||
}
|
||||
allowDowncast = true;
|
||||
}
|
||||
data.clearLanedAccessList();
|
||||
data.clearLanedAccessMap();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1238,14 +1114,30 @@ int4 ActionDeindirect::apply(Funcdata &data)
|
|||
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)
|
||||
|
||||
{
|
||||
Architecture *glb = data.getArch();
|
||||
bool cachereadonly = glb->readonlypropagate;
|
||||
if (glb->userops.getVolatileRead() == (VolatileReadOp *)0) {
|
||||
if (!cachereadonly)
|
||||
return 0; // Nothing to do to special properties
|
||||
int4 minLanedSize = 1000000; // Default size meant to filter no Varnodes
|
||||
if (!data.isLanedRegComplete()) {
|
||||
int4 sz = glb->getMinimumLanedRegisterSize();
|
||||
if (sz > 0)
|
||||
minLanedSize = sz;
|
||||
}
|
||||
VarnodeLocSet::const_iterator iter;
|
||||
Varnode *vn;
|
||||
|
@ -1254,6 +1146,9 @@ int4 ActionVarnodeProps::apply(Funcdata &data)
|
|||
while(iter != data.endLoc()) {
|
||||
vn = *iter++; // Advance iterator in case vn is deleted
|
||||
if (vn->isAnnotation()) continue;
|
||||
int4 vnSize = vn->getSize();
|
||||
if (vnSize >= minLanedSize)
|
||||
markLanedVarnode(data, vn);
|
||||
if (vn->hasActionProperty()) {
|
||||
if (cachereadonly&&vn->isReadOnly()) {
|
||||
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))
|
||||
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
|
||||
if (vn->isConstant()) continue; // Don't replace a constant
|
||||
if (vn->isWritten()) {
|
||||
|
@ -1283,6 +1178,7 @@ int4 ActionVarnodeProps::apply(Funcdata &data)
|
|||
}
|
||||
}
|
||||
}
|
||||
data.setLanedRegGenerated();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -4714,7 +4610,6 @@ void universal_action(Architecture *conf)
|
|||
// actmainloop->addAction( new ActionParamShiftStop("paramshift") );
|
||||
actmainloop->addAction( new ActionRestrictLocal("localrecovery") ); // Do before dead code removed
|
||||
actmainloop->addAction( new ActionDeadCode("deadcode") );
|
||||
actmainloop->addAction( new ActionCollectLanedAccess("base") );
|
||||
actmainloop->addAction( new ActionDynamicMapping("dynamic") ); // Must come before restructurevarnode and infertypes
|
||||
actmainloop->addAction( new ActionRestructureVarnode("localrecovery") );
|
||||
actmainloop->addAction( new ActionSpacebase("base") ); // Must come before infertypes and nonzeromask
|
||||
|
|
|
@ -97,26 +97,6 @@ public:
|
|||
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
|
||||
///
|
||||
/// 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
|
||||
/// rewrites the data-flow so that the lanes become explicit Varnodes.
|
||||
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:
|
||||
ActionLaneDivide(const string &g) : Action(rule_onceperfunc,"lanedivide",g) {} ///< Constructor
|
||||
virtual Action *clone(const ActionGroupList &grouplist) const {
|
||||
|
@ -222,8 +202,15 @@ public:
|
|||
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 {
|
||||
void markLanedVarnode(Funcdata &data,Varnode *vn); ///< Mark possible laned register storage
|
||||
public:
|
||||
ActionVarnodeProps(const string &g) : Action(0,"varnodeprops",g) {} ///< Constructor
|
||||
virtual Action *clone(const ActionGroupList &grouplist) const {
|
||||
|
|
|
@ -56,7 +56,8 @@ class Funcdata {
|
|||
restart_pending = 0x200, ///< Analysis must be restarted (because of new override info)
|
||||
unimplemented_present = 0x400, ///< Set if function contains unimplemented instructions
|
||||
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 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
|
||||
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
|
||||
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
|
||||
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 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
|
||||
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
|
||||
///
|
||||
|
@ -347,6 +350,11 @@ public:
|
|||
/// \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); }
|
||||
|
||||
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
|
||||
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;
|
||||
|
@ -429,10 +437,6 @@ public:
|
|||
Varnode *opStackLoad(AddrSpace *spc,uintb off,uint4 sz,PcodeOp *op,Varnode *stackptr,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 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
|
||||
list<PcodeOp *>::const_iterator beginOp(OpCode opc) const { return obank.begin(opc); }
|
||||
|
|
|
@ -557,19 +557,6 @@ void Funcdata::opUndoPtradd(PcodeOp *op,bool finalize)
|
|||
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
|
||||
/// is \e not cloned.
|
||||
/// \param op is the PcodeOp to clone
|
||||
|
|
|
@ -286,6 +286,21 @@ void Funcdata::destroyVarnode(Varnode *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
|
||||
/// 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.
|
||||
|
|
|
@ -276,8 +276,10 @@ bool LanedRegister::restoreXml(const Element *el,const AddrSpaceManager *manage)
|
|||
}
|
||||
}
|
||||
if (laneSizes.empty()) return false;
|
||||
VarnodeData storage;
|
||||
storage.space = (AddrSpace *)0;
|
||||
storage.restoreXml(el, manage);
|
||||
wholeSize = storage.size;
|
||||
sizeBitMask = 0;
|
||||
string::size_type pos = 0;
|
||||
while(pos != string::npos) {
|
||||
|
@ -299,23 +301,11 @@ bool LanedRegister::restoreXml(const Element *el,const AddrSpaceManager *manage)
|
|||
s >> sz;
|
||||
if (sz < 0 || sz > 16)
|
||||
throw LowlevelError("Bad lane size: " + value);
|
||||
addSize(sz);
|
||||
addLaneSize(sz);
|
||||
}
|
||||
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)
|
||||
|
||||
{
|
||||
|
|
|
@ -86,30 +86,16 @@ public:
|
|||
|
||||
/// \brief Describes a (register) storage location and the ways it might be split into lanes
|
||||
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
|
||||
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
|
||||
const VarnodeData &getStorage(void) const { return storage; } ///< Get VarnodeData for storage
|
||||
void addSize(int4 size) { sizeBitMask |= ((uint4)1 << size); } ///< Add a new \e size to the allowed list
|
||||
int4 getWholeSize(void) const { return wholeSize; } ///< Get the size in bytes of the whole laned register
|
||||
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 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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue