GP-2767 Structured pieces

This commit is contained in:
caheckman 2022-10-27 16:43:58 -04:00
parent b707c2ea6b
commit 535ac7c08d
29 changed files with 834 additions and 210 deletions

View file

@ -750,6 +750,90 @@ int4 PcodeOp::compareOrder(const PcodeOp *bop) const
return 0;
}
/// \brief Determine if a Varnode is a leaf within the CONCAT tree rooted at the given Varnode
///
/// The CONCAT tree is the maximal set of Varnodes that are all inputs to CPUI_PIECE operations,
/// with no other uses, and that all ultimately flow to the root Varnode. This method tests
/// whether a Varnode is a leaf of this tree.
/// \param rootVn is the given root of the CONCAT tree
/// \param vn is the Varnode to test as a leaf
/// \param typeOffset is byte offset of the test Varnode within fully concatenated value
/// \return \b true is the test Varnode is a leaf of the tree
bool PieceNode::isLeaf(Varnode *rootVn,Varnode *vn,int4 typeOffset)
{
if (vn->isMapped() && rootVn->getSymbolEntry() != vn->getSymbolEntry()) {
return true;
}
if (!vn->isWritten()) return true;
PcodeOp *def = vn->getDef();
if (def->code() != CPUI_PIECE) return true;
PcodeOp *op = vn->loneDescend();
if (op == (PcodeOp *)0) return true;
if (vn->isAddrTied()) {
Address addr = rootVn->getAddr() + typeOffset;
if (vn->getAddr() != addr) return true;
}
return false;
}
/// Find the root of the CONCAT tree of Varnodes marked either isProtoPartial() or isAddrTied().
/// This will be the maximal Varnode that containing the given Varnode (as storage), with a
/// backward path to it through PIECE operations. All Varnodes along the path, except the root, will be
/// marked as isProtoPartial() or isAddrTied().
/// \return the root of the CONCAT tree
Varnode *PieceNode::findRoot(Varnode *vn)
{
while(vn->isProtoPartial() || vn->isAddrTied()) {
list<PcodeOp *>::const_iterator iter = vn->beginDescend();
PcodeOp *pieceOp = (PcodeOp *)0;
while(iter != vn->endDescend()) {
PcodeOp *op = *iter;
++iter;
if (op->code() != CPUI_PIECE) continue;
int4 slot = op->getSlot(vn);
Address addr = op->getOut()->getAddr();
if (addr.getSpace()->isBigEndian() == (slot == 1))
addr = addr + op->getIn(1-slot)->getSize();
if (addr == vn->getAddr()) {
if (pieceOp != (PcodeOp *)0) { // If there is more than one valid PIECE
if (op->compareOrder(pieceOp)) // Attach this to earliest one
pieceOp = op;
}
else
pieceOp = op;
}
}
if (pieceOp == (PcodeOp *)0)
break;
vn = pieceOp->getOut();
}
return vn;
}
/// \brief Build the CONCAT tree rooted at the given Varnode
///
/// Recursively walk backwards from the root through CPUI_PIECE operations, stopping if a Varnode
/// is deemed a leaf. Collect all Varnodes involved in the tree in a list. For each Varnode in the tree,
/// record whether it is leaf and also calculate its offset within the data-type attached to the root.
/// \param stack holds the markup for each node of the tree
/// \param rootVn is the given root of the tree
/// \param op is the current PIECE op to explore as part of the tree
/// \param baseOffset is the offset associated with the output of the current PIECE op
void PieceNode::gatherPieces(vector<PieceNode> &stack,Varnode *rootVn,PcodeOp *op,int4 baseOffset)
{
for(int4 i=0;i<2;++i) {
Varnode *vn = op->getIn(i);
int4 offset = (rootVn->getSpace()->isBigEndian() == (i==1)) ? baseOffset + op->getIn(1-i)->getSize() : baseOffset;
bool res = isLeaf(rootVn,vn,offset);
stack.emplace_back(op,i,offset,res);
if (!res)
gatherPieces(stack,rootVn,vn->getDef(),offset);
}
}
/// Add the PcodeOp to the list of ops with the same op-code. Currently only certain
/// op-codes have a dedicated list.
/// \param op is the given PcodeOp