New LaneDescription methods, refactor TransformVar initialize

This commit is contained in:
caheckman 2019-10-17 09:49:24 -04:00
parent ad87a8d40f
commit 4f925923c5
2 changed files with 148 additions and 55 deletions

View file

@ -49,6 +49,81 @@ LaneDescription::LaneDescription(int4 origSize,int4 lo,int4 hi)
lanePosition[1] = lo; lanePosition[1] = lo;
} }
/// Position 0 will map to index 0 and a position equal to whole size will
/// map to the number of lanes. Positions that are out of bounds or that do
/// not fall on a lane boundary will return -1.
/// \param bytePos is the given byte position to test
/// \return the index of the lane that start at the given position
int4 LaneDescription::getBoundary(int4 bytePos) const
{
if (bytePos < 0 || bytePos > wholeSize)
return -1;
if (bytePos == wholeSize)
return lanePosition.size();
int4 min = 0;
int4 max = lanePosition.size() - 1;
while(min < max) {
int4 index = (min + max) / 2;
int4 pos = lanePosition[index];
if (pos == bytePos) return index;
if (pos < bytePos)
min = pos + 1;
else
max = pos - 1;
}
return -1;
}
/// \brief Decide if a given truncation is natural for \b this description
///
/// A subset of lanes are specified and a truncation (given by a byte position and byte size).
/// If the truncation, relative to the subset, contains at least 1 lane and does not split any
/// lanes, then return \b true and pass back the number of lanes and starting lane of the truncation.
/// \param numLanes is the number of lanes in the original subset
/// \param skipLanes is the starting (least significant) lane index of the original subset
/// \param bytePos is the number of bytes to truncate from the front (least significant portion) of the subset
/// \param size is the number of bytes to include in the truncation
/// \param resNumLanes will hold the number of lanes in the truncation
/// \param resSkipLanes will hold the starting lane in the truncation
/// \return \b true if the truncation is natural
bool LaneDescription::restriction(int4 numLanes,int4 skipLanes,int4 bytePos,int4 size,
int4 &resNumLanes,int4 &resSkipLanes) const
{
resSkipLanes = getBoundary(lanePosition[skipLanes] + bytePos);
if (resSkipLanes < 0) return false;
int4 finalIndex = getBoundary(lanePosition[skipLanes] + bytePos + size);
if (finalIndex < 0) return false;
resNumLanes = finalIndex - resSkipLanes;
return (resNumLanes != 0);
}
/// \brief Decide if a given subset of lanes can be extended naturally for \b this description
///
/// A subset of lanes are specified and their position within an extension (given by a byte position).
/// The size in bytes of the extension is also given. If the extension is contained within \b this description,
/// and the boundaries of the extension don't split any lanes, then return \b true and pass back
/// the number of lanes and starting lane of the extension.
/// \param numLanes is the number of lanes in the original subset
/// \param skipLanes is the starting (least significant) lane index of the original subset
/// \param bytePos is the number of bytes to truncate from the front (least significant portion) of the extension
/// \param size is the number of bytes in the extension
/// \param resNumLanes will hold the number of lanes in the extension
/// \param resSkipLanes will hold the starting lane in the extension
/// \return \b true if the extension is natural
bool LaneDescription::extension(int4 numLanes,int4 skipLanes,int4 bytePos,int4 size,
int4 &resNumLanes,int4 &resSkipLanes) const
{
resSkipLanes = getBoundary(lanePosition[skipLanes] - bytePos);
if (resSkipLanes < 0) return false;
int4 finalIndex = getBoundary(lanePosition[skipLanes] - bytePos + size);
if (finalIndex < 0) return false;
resNumLanes = finalIndex - resSkipLanes;
return (resNumLanes != 0);
}
/// Create the Varnode object (constant, unique, vector piece) described by the /// Create the Varnode object (constant, unique, vector piece) described by the
/// given placeholder. If the Varnode is an output, assume the op already exists /// given placeholder. If the Varnode is an output, assume the op already exists
/// and create the Varnode as an output. Set the \b replacement field with the /// and create the Varnode as an output. Set the \b replacement field with the
@ -193,14 +268,10 @@ TransformVar *TransformManager::newPreexistingVarnode(Varnode *vn)
{ {
TransformVar *res = new TransformVar[1]; TransformVar *res = new TransformVar[1];
pieceMap[vn->getCreateIndex()] = res; // Enter preexisting Varnode into map, so we don't make another placeholder pieceMap[vn->getCreateIndex()] = res; // Enter preexisting Varnode into map, so we don't make another placeholder
res->vn = vn;
res->replacement = (Varnode *)0; // value of 0 treats this as "piece" of itself at offset 0, allows getPiece() to find it
res->byteSize = vn->getSize(); res->initialize(TransformVar::preexisting,vn,vn->getSize()*8,vn->getSize(),0);
res->bitSize = res->byteSize * 8;
res->def = (TransformOp *)0;
res->type = TransformVar::preexisting;
res->flags = TransformVar::split_terminator; res->flags = TransformVar::split_terminator;
res->val = 0; // Treat this as "piece" of itself at offset 0, allows getPiece() to find this
return res; return res;
} }
@ -211,13 +282,7 @@ TransformVar *TransformManager::newUnique(int4 size)
{ {
newVarnodes.push_back(TransformVar()); newVarnodes.push_back(TransformVar());
TransformVar *res = &newVarnodes.back(); TransformVar *res = &newVarnodes.back();
res->vn = (Varnode *)0; res->initialize(TransformVar::normal_temp,(Varnode *)0,size*8,size,0);
res->replacement = (Varnode *)0;
res->byteSize = size;
res->bitSize = size * 8;
res->def = (TransformOp *)0;
res->type = TransformVar::normal_temp;
res->flags = 0;
return res; return res;
} }
@ -232,30 +297,19 @@ TransformVar *TransformManager::newConstant(int4 size,int4 lsbOffset,uintb val)
{ {
newVarnodes.push_back(TransformVar()); newVarnodes.push_back(TransformVar());
TransformVar *res = &newVarnodes.back(); TransformVar *res = &newVarnodes.back();
res->vn = (Varnode *)0; res->initialize(TransformVar::constant,(Varnode *)0,size*8,size,(val >> lsbOffset) & calc_mask(size));
res->replacement = (Varnode *)0;
res->byteSize = size;
res->bitSize = size * 8;
res->val = (val >> lsbOffset) & calc_mask(size);
res->def = (TransformOp *)0;
res->type = TransformVar::constant;
res->flags = 0;
return res; return res;
} }
/// Used for creating INDIRECT placeholders.
/// \param vn is the original iop parameter to the INDIRECT
/// \return the new placeholder node
TransformVar *TransformManager::newIop(Varnode *vn) TransformVar *TransformManager::newIop(Varnode *vn)
{ {
newVarnodes.push_back(TransformVar()); newVarnodes.push_back(TransformVar());
TransformVar *res = &newVarnodes.back(); TransformVar *res = &newVarnodes.back();
res->vn = (Varnode *)0; res->initialize(TransformVar::constant_iop,(Varnode *)0,vn->getSize()*8,vn->getSize(),vn->getOffset());
res->replacement = (Varnode *)0;
res->byteSize = vn->getSize();
res->bitSize = res->byteSize * 8;
res->val = vn->getOffset(); // The encoded iop
res->def = (TransformOp *)0;
res->type = TransformVar::constant_iop;
res->flags = 0;
return res; return res;
} }
@ -270,17 +324,10 @@ TransformVar *TransformManager::newPiece(Varnode *vn,int4 bitSize,int4 lsbOffset
{ {
TransformVar *res = new TransformVar[1]; TransformVar *res = new TransformVar[1];
pieceMap[vn->getCreateIndex()] = res; pieceMap[vn->getCreateIndex()] = res;
res->vn = vn; int4 byteSize = (bitSize + 7) / 8;
res->replacement = (Varnode *)0; uint4 type = preserveAddress(vn, bitSize, lsbOffset) ? TransformVar::piece : TransformVar::piece_temp;
res->bitSize = bitSize; res->initialize(type, vn, bitSize, byteSize, lsbOffset);
res->byteSize = (bitSize + 7) / 8;
res->def = (TransformOp *)0;
if (preserveAddress(vn, bitSize, lsbOffset))
res->type = TransformVar::piece;
else
res->type = TransformVar::piece_temp;
res->flags = TransformVar::split_terminator; res->flags = TransformVar::split_terminator;
res->val = lsbOffset;
return res; return res;
} }
@ -300,28 +347,47 @@ TransformVar *TransformManager::newSplit(Varnode *vn,const LaneDescription &desc
for(int4 i=0;i<num;++i) { for(int4 i=0;i<num;++i) {
int4 bitpos = description.getPosition(i) * 8; int4 bitpos = description.getPosition(i) * 8;
TransformVar *newVar = &res[i]; TransformVar *newVar = &res[i];
newVar->vn = vn; int4 byteSize = description.getSize(i);
newVar->replacement = (Varnode *)0; if (vn->isConstant())
newVar->byteSize = description.getSize(i); newVar->initialize(TransformVar::constant,vn,byteSize * 8,byteSize, (vn->getOffset() >> bitpos) & calc_mask(byteSize));
newVar->bitSize = newVar->byteSize * 8;
newVar->def = (TransformOp *)0;
newVar->flags = 0;
if (vn->isConstant()) {
newVar->type = TransformVar::constant;
newVar->val = (vn->getOffset() >> bitpos) & calc_mask(newVar->byteSize);
}
else { else {
if (preserveAddress(vn, newVar->bitSize, bitpos)) uint4 type = preserveAddress(vn, byteSize * 8, bitpos) ? TransformVar::piece : TransformVar::piece_temp;
newVar->type = TransformVar::piece; newVar->initialize(type,vn,byteSize * 8, byteSize, bitpos);
else
newVar->type = TransformVar::piece_temp;
newVar->val = bitpos;
} }
} }
res[num-1].flags = TransformVar::split_terminator; res[num-1].flags = TransformVar::split_terminator;
return res; return res;
} }
/// \brief Create placeholder nodes splitting a Varnode into a subset of lanes in the given description
///
/// Given a big Varnode and specific subset of a lane description, create placeholders for all
/// the explicit pieces that the big Varnode will be split into.
/// \param vn is the big Varnode to split
/// \param description gives a list of potentional lanes
/// \param numLanes is the number of lanes in the subset
/// \param startLane is the starting (least significant) lane in the subset
/// \return an array of the new TransformVar placeholders from least to most significant
TransformVar *TransformManager::newSplit(Varnode *vn,const LaneDescription &description,int4 numLanes,int4 startLane)
{
TransformVar *res = new TransformVar[numLanes];
pieceMap[vn->getCreateIndex()] = res;
for(int4 i=0;i<numLanes;++i) {
int4 bitpos = description.getPosition(startLane + i) * 8;
int4 byteSize = description.getSize(startLane + i);
TransformVar *newVar = &res[i];
if (vn->isConstant())
newVar->initialize(TransformVar::constant,vn,byteSize * 8, byteSize, (vn->getOffset() >> bitpos) & calc_mask(byteSize));
else {
uint4 type = preserveAddress(vn, byteSize * 8, bitpos) ? TransformVar::piece : TransformVar::piece_temp;
newVar->initialize(type,vn,byteSize * 8, byteSize, bitpos);
}
}
res[numLanes-1].flags = TransformVar::split_terminator;
return res;
}
/// \brief Create a new placeholder op intended to replace an existing op /// \brief Create a new placeholder op intended to replace an existing op
/// ///
/// An uninitialized placeholder for the new op is created. /// An uninitialized placeholder for the new op is created.

View file

@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/// \file transform.hh
/// \brief Classes for building large scale transforms of function data-flow
#ifndef __TRANSFORM__ #ifndef __TRANSFORM__
#define __TRANSFORM__ #define __TRANSFORM__
@ -49,6 +51,7 @@ private:
uintb val; ///< Value of constant or (bit) position within the original big Varnode uintb val; ///< Value of constant or (bit) position within the original big Varnode
TransformOp *def; ///< Defining op for new Varnode TransformOp *def; ///< Defining op for new Varnode
void createReplacement(Funcdata *fd); ///< Create the new/modified variable this placeholder represents void createReplacement(Funcdata *fd); ///< Create the new/modified variable this placeholder represents
void initialize(uint4 tp,Varnode *v,int4 bits,int4 bytes,uintb value);
public: public:
Varnode *getOriginal(void) const { return vn; } ///< Get the original Varnode \b this placeholder models Varnode *getOriginal(void) const { return vn; } ///< Get the original Varnode \b this placeholder models
TransformOp *getDef(void) const { return def; } ///< Get the operator that defines this placeholder variable TransformOp *getDef(void) const { return def; } ///< Get the operator that defines this placeholder variable
@ -97,6 +100,9 @@ public:
int4 getWholeSize(void) const { return wholeSize; } ///< Get the size of the region being split int4 getWholeSize(void) const { return wholeSize; } ///< Get the size of the region being split
int4 getSize(int4 i) const { return laneSize[i]; } ///< Get the size of the i-th lane int4 getSize(int4 i) const { return laneSize[i]; } ///< Get the size of the i-th lane
int4 getPosition(int4 i) const { return lanePosition[i]; } ///< Get the significance offset of the i-th lane int4 getPosition(int4 i) const { return lanePosition[i]; } ///< Get the significance offset of the i-th lane
int4 getBoundary(int4 bytePos) const; ///< Get index of lane that starts at the given byte position
bool restriction(int4 numLanes,int4 skipLanes,int4 bytePos,int4 size,int4 &resNumLanes,int4 &resSkipLanes) const;
bool extension(int4 numLanes,int4 skipLanes,int4 bytePos,int4 size,int4 &resNumLanes,int4 &resSkipLanes) const;
}; };
/// \brief Class for splitting larger registers holding smaller logical lanes /// \brief Class for splitting larger registers holding smaller logical lanes
@ -129,6 +135,7 @@ public:
TransformVar *newIop(Varnode *vn); ///< Make placeholder for special iop constant TransformVar *newIop(Varnode *vn); ///< Make placeholder for special iop constant
TransformVar *newPiece(Varnode *vn,int4 bitSize,int4 lsbOffset); ///< Make placeholder for piece of a Varnode TransformVar *newPiece(Varnode *vn,int4 bitSize,int4 lsbOffset); ///< Make placeholder for piece of a Varnode
TransformVar *newSplit(Varnode *vn,const LaneDescription &description); TransformVar *newSplit(Varnode *vn,const LaneDescription &description);
TransformVar *newSplit(Varnode *vn,const LaneDescription &description,int4 numLanes,int4 startLane);
TransformOp *newOpReplace(int4 numParams,OpCode opc,PcodeOp *replace); TransformOp *newOpReplace(int4 numParams,OpCode opc,PcodeOp *replace);
TransformOp *newOp(int4 numParams,OpCode opc,TransformOp *follow); TransformOp *newOp(int4 numParams,OpCode opc,TransformOp *follow);
TransformOp *newPreexistingOp(int4 numParams,OpCode opc,PcodeOp *originalOp); TransformOp *newPreexistingOp(int4 numParams,OpCode opc,PcodeOp *originalOp);
@ -142,6 +149,26 @@ public:
void apply(void); ///< Apply the full transform to the function void apply(void); ///< Apply the full transform to the function
}; };
/// \brief Initialize \b this variable from raw data
///
/// \param tp is the type of variable to create
/// \param v is the underlying Varnode of which this is a piece (may be null)
/// \param bits is the number of bits in the variable
/// \param bytes is the number of bytes in the variable
/// \param value is the associated value
inline void TransformVar::initialize(uint4 tp,Varnode *v,int4 bits,int4 bytes,uintb value)
{
type = tp;
vn = v;
val = value;
bitSize = bits;
byteSize = bytes;
flags = 0;
def = (TransformOp *)0;
replacement = (Varnode *)0;
}
/// \param rop is the given placeholder op whose input is set /// \param rop is the given placeholder op whose input is set
/// \param rvn is the placeholder variable to set /// \param rvn is the placeholder variable to set
/// \param slot is the input position to set /// \param slot is the input position to set