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;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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); }
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue