mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-25 05:32:14 +00:00
Expanded RulePushPtr and RuleExtensionPush
This commit is contained in:
parent
9c952ed154
commit
c9ba3640bf
@ -11,8 +11,9 @@ src/decompile/cpp/Doxyfile||GHIDRA|||Most of this file is autogenerated by doxyg
|
|||||||
src/decompile/cpp/Makefile||GHIDRA||||END|
|
src/decompile/cpp/Makefile||GHIDRA||||END|
|
||||||
src/decompile/datatests/convert.xml||GHIDRA||||END|
|
src/decompile/datatests/convert.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/deadvolatile.xml||GHIDRA||||END|
|
src/decompile/datatests/deadvolatile.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/elseif.xml||GHIDRA||||END|
|
|
||||||
src/decompile/datatests/deindirect.xml||GHIDRA||||END|
|
src/decompile/datatests/deindirect.xml||GHIDRA||||END|
|
||||||
|
src/decompile/datatests/dupptr.xml||GHIDRA||||END|
|
||||||
|
src/decompile/datatests/elseif.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/floatprint.xml||GHIDRA||||END|
|
src/decompile/datatests/floatprint.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/forloop1.xml||GHIDRA||||END|
|
src/decompile/datatests/forloop1.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/forloop_loaditer.xml||GHIDRA||||END|
|
src/decompile/datatests/forloop_loaditer.xml||GHIDRA||||END|
|
||||||
|
@ -5174,6 +5174,7 @@ void ActionDatabase::universalAction(Architecture *conf)
|
|||||||
actcleanup->addRule( new Rule2Comp2Sub("cleanup") );
|
actcleanup->addRule( new Rule2Comp2Sub("cleanup") );
|
||||||
actcleanup->addRule( new RuleSubRight("cleanup") );
|
actcleanup->addRule( new RuleSubRight("cleanup") );
|
||||||
actcleanup->addRule( new RulePtrsubCharConstant("cleanup") );
|
actcleanup->addRule( new RulePtrsubCharConstant("cleanup") );
|
||||||
|
actcleanup->addRule( new RuleExtensionPush("cleanup") );
|
||||||
}
|
}
|
||||||
act->addAction( actcleanup );
|
act->addAction( actcleanup );
|
||||||
|
|
||||||
|
@ -6098,74 +6098,81 @@ void AddTreeState::buildTree(void)
|
|||||||
data.opDestroy(baseOp);
|
data.opDestroy(baseOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Verify that given PcodeOp occurs at the bottom of the CPUI_INT_ADD tree
|
|
||||||
///
|
|
||||||
/// The main RulePtrArith algorithm assumes that the pointer Varnode is at the bottom
|
|
||||||
/// of the expression tree that is adding an offset to the pointer. This routine
|
|
||||||
/// verifies this condition.
|
|
||||||
/// \param op is the given PcodeOp which is the putative last operation in the tree
|
|
||||||
/// \param slot is the slot of the pointer Varnode within the given PcodeOp
|
|
||||||
/// \return \b true if the pointer is at the bottom of the tree, \b false otherwise
|
|
||||||
bool RulePtrArith::verifyAddTreeBottom(PcodeOp *op,int4 slot)
|
|
||||||
|
|
||||||
{
|
|
||||||
Varnode *vn = op->getOut();
|
|
||||||
Varnode *ptrbase = op->getIn(slot);
|
|
||||||
list<PcodeOp *>::const_iterator iter=vn->beginDescend();
|
|
||||||
OpCode opc;
|
|
||||||
if (iter == vn->endDescend()) return false; // Don't bother if no descendants
|
|
||||||
PcodeOp *lowerop = *iter++;
|
|
||||||
opc = lowerop->code();
|
|
||||||
if (vn->isSpacebase()) // For the RESULT to be a spacebase pointer
|
|
||||||
if (iter!=vn->endDescend()) // It must have only 1 descendant
|
|
||||||
return false;
|
|
||||||
if (opc == CPUI_INT_ADD) // Check for lone descendant which is an ADD
|
|
||||||
if (iter==vn->endDescend())
|
|
||||||
return false; // this is not bottom of add tree
|
|
||||||
if (ptrbase->isSpacebase() && (ptrbase->isInput()||(ptrbase->isConstant())) &&
|
|
||||||
(op->getIn(1-slot)->isConstant())) {
|
|
||||||
// Look for ANY descendant which LOADs or STOREs off of vn
|
|
||||||
if ((opc==CPUI_LOAD)||(opc==CPUI_STORE)) {
|
|
||||||
if (lowerop->getIn(1) == vn)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
while(iter!=vn->endDescend()) {
|
|
||||||
opc = (*iter)->code();
|
|
||||||
if ((opc==CPUI_LOAD)||(opc==CPUI_STORE)) {
|
|
||||||
if ((*iter)->getIn(1) == vn)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Test for other pointers in the ADD tree above the given op that might be a preferred base
|
/// \brief Test for other pointers in the ADD tree above the given op that might be a preferred base
|
||||||
///
|
///
|
||||||
/// This tests the condition of RulePushPtr, making sure that the given op isn't the lone descendant
|
/// This tests the condition of RulePushPtr on the node immediately above the given putative base pointer
|
||||||
/// of a pointer constructed by INT_ADD on another pointer (which would then be preferred).
|
|
||||||
/// \param op is the given op
|
/// \param op is the given op
|
||||||
/// \param slot is the input slot of the pointer
|
/// \param slot is the input slot of the putative base pointer
|
||||||
/// \return \b true if the indicated slot holds the preferred pointer
|
/// \return \b true if the indicated slot holds the preferred pointer
|
||||||
bool RulePtrArith::verifyPreferredPointer(PcodeOp *op,int4 slot)
|
bool RulePtrArith::verifyPreferredPointer(PcodeOp *op,int4 slot)
|
||||||
|
|
||||||
{
|
{
|
||||||
Varnode *vn = op->getIn(slot);
|
Varnode *vn = op->getIn(slot);
|
||||||
// Check if RulePushPtr would apply here
|
if (!vn->isWritten()) return true;
|
||||||
if (op->getIn(1-slot)->getType()->getMetatype() != TYPE_PTR && vn->isWritten()) {
|
PcodeOp *preOp = vn->getDef();
|
||||||
PcodeOp *preOp = vn->getDef();
|
if (preOp->code() != CPUI_INT_ADD) return true;
|
||||||
if (preOp->code() == CPUI_INT_ADD) {
|
int preslot = 0;
|
||||||
if (vn->loneDescend() == op) {
|
if (preOp->getIn(preslot)->getType()->getMetatype() != TYPE_PTR) {
|
||||||
int ptrCount = 0;
|
preslot = 1;
|
||||||
if (preOp->getIn(0)->getType()->getMetatype() == TYPE_PTR) ptrCount += 1;
|
if (preOp->getIn(preslot)->getType()->getMetatype() != TYPE_PTR)
|
||||||
if (preOp->getIn(1)->getType()->getMetatype() == TYPE_PTR) ptrCount += 1;
|
return true;
|
||||||
if (ptrCount == 1)
|
}
|
||||||
return false; // RulePushPtr would apply, so we are not preferred
|
return (1 != evaluatePointerExpression(preOp, preslot)); // Does earlier varnode look like the base pointer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Determine if the expression rooted at the given INT_ADD operation is ready for conversion
|
||||||
|
///
|
||||||
|
/// Converting an expression of INT_ADDs into PTRSUBs and PTRADDs requires that the base pointer
|
||||||
|
/// be at the root of the expression tree. This method evaluates whether given root has the base
|
||||||
|
/// pointer at the bottom. If not, a \e push transform needs to be performed before RulePtrArith can apply.
|
||||||
|
/// This method returns a command code:
|
||||||
|
/// - 0 if no action should be taken, the expression is not fully linked or should not be converted
|
||||||
|
/// - 1 if a \e push action should be taken, prior to conversion
|
||||||
|
/// - 2 if the pointer arithmetic conversion can proceed
|
||||||
|
/// \param op is the given INT_ADD
|
||||||
|
/// \param slot is the index of the pointer
|
||||||
|
/// \return the command code
|
||||||
|
int4 RulePtrArith::evaluatePointerExpression(PcodeOp *op,int4 slot)
|
||||||
|
|
||||||
|
{
|
||||||
|
int4 res = 1; // Assume we are going to push
|
||||||
|
int4 count = 0; // Count descendants
|
||||||
|
Varnode *ptrBase = op->getIn(slot);
|
||||||
|
if (ptrBase->isFree() && !ptrBase->isConstant())
|
||||||
|
return 0;
|
||||||
|
if (op->getIn(1 - slot)->getType()->getMetatype() == TYPE_PTR)
|
||||||
|
res = 2;
|
||||||
|
Varnode *outVn = op->getOut();
|
||||||
|
list<PcodeOp *>::const_iterator iter;
|
||||||
|
for(iter=outVn->beginDescend();iter!=outVn->endDescend();++iter) {
|
||||||
|
PcodeOp *decOp = *iter;
|
||||||
|
count += 1;
|
||||||
|
OpCode opc = decOp->code();
|
||||||
|
if (opc == CPUI_INT_ADD) {
|
||||||
|
Varnode *otherVn = decOp->getIn(1 - decOp->getSlot(outVn));
|
||||||
|
if (otherVn->isFree() && !otherVn->isConstant())
|
||||||
|
return 0; // No action if the data-flow isn't fully linked
|
||||||
|
if (otherVn->getType()->getMetatype() == TYPE_PTR)
|
||||||
|
res = 2; // Do not push in the presence of other pointers
|
||||||
|
}
|
||||||
|
else if ((opc == CPUI_LOAD || opc == CPUI_STORE) && decOp->getIn(1) == outVn) { // If use is as pointer for LOAD or STORE
|
||||||
|
if (ptrBase->isSpacebase() && (ptrBase->isInput()||(ptrBase->isConstant())) &&
|
||||||
|
(op->getIn(1-slot)->isConstant()))
|
||||||
|
return 0;
|
||||||
|
res = 2;
|
||||||
|
}
|
||||||
|
else { // Any other op besides ADD, do not push
|
||||||
|
res = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
if (count == 0)
|
||||||
|
return 0;
|
||||||
|
if (count > 1) {
|
||||||
|
if (outVn->isSpacebase())
|
||||||
|
return 0; // For the RESULT to be a spacebase pointer it must have only 1 descendent
|
||||||
|
// res = 2; // Uncommenting this line will not let pointers get pushed to multiple descendants
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \class RulePtrArith
|
/// \class RulePtrArith
|
||||||
@ -6206,7 +6213,7 @@ int4 RulePtrArith::applyOp(PcodeOp *op,Funcdata &data)
|
|||||||
if (ct->getMetatype() == TYPE_PTR) break;
|
if (ct->getMetatype() == TYPE_PTR) break;
|
||||||
}
|
}
|
||||||
if (slot == op->numInput()) return 0;
|
if (slot == op->numInput()) return 0;
|
||||||
if (!verifyAddTreeBottom(op, slot)) return 0;
|
if (evaluatePointerExpression(op, slot) != 2) return 0;
|
||||||
if (!verifyPreferredPointer(op, slot)) return 0;
|
if (!verifyPreferredPointer(op, slot)) return 0;
|
||||||
|
|
||||||
const TypePointer *tp = (const TypePointer *) ct;
|
const TypePointer *tp = (const TypePointer *) ct;
|
||||||
@ -6298,6 +6305,82 @@ int4 RuleStructOffset0::applyOp(PcodeOp *op,Funcdata &data)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Build a duplicate of the given Varnode as an output of a PcodeOp, preserving the storage address if possible
|
||||||
|
///
|
||||||
|
/// If the Varnode is already a \e unique or is \e addrtied
|
||||||
|
/// \param vn is the given Varnode
|
||||||
|
/// \param op is the PcodeOp to which the duplicate should be an output
|
||||||
|
/// \param data is the function to add the duplicate to
|
||||||
|
/// \return the duplicate Varnode
|
||||||
|
Varnode *RulePushPtr::buildVarnodeOut(Varnode *vn,PcodeOp *op,Funcdata &data)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (vn->isAddrTied() || vn->getSpace()->getType() == IPTR_INTERNAL)
|
||||||
|
return data.newUniqueOut(vn->getSize(), op);
|
||||||
|
return data.newVarnodeOut(vn->getSize(), vn->getAddr(), op);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Generate list of PcodeOps that need to be duplicated as part of pushing the pointer
|
||||||
|
///
|
||||||
|
/// If the pointer INT_ADD is duplicated as part of the push, some of the operations building
|
||||||
|
/// the offset to the pointer may also need to be duplicated. Identify these and add them
|
||||||
|
/// to the result list.
|
||||||
|
/// \param reslist is the result list to be populated
|
||||||
|
/// \param vn is the offset Varnode being added to the pointer
|
||||||
|
void RulePushPtr::collectDuplicateNeeds(vector<PcodeOp *> &reslist,Varnode *vn)
|
||||||
|
|
||||||
|
{
|
||||||
|
for(;;) {
|
||||||
|
if (!vn->isWritten()) return;
|
||||||
|
if (vn->isAutoLive()) return;
|
||||||
|
if (vn->loneDescend() == (PcodeOp *)0) return; // Already has multiple descendants
|
||||||
|
PcodeOp *op = vn->getDef();
|
||||||
|
OpCode opc = op->code();
|
||||||
|
if (opc == CPUI_INT_ZEXT || opc == CPUI_INT_SEXT || opc == CPUI_INT_2COMP)
|
||||||
|
reslist.push_back(op);
|
||||||
|
else if (opc == CPUI_INT_MULT) {
|
||||||
|
if (op->getIn(1)->isConstant())
|
||||||
|
reslist.push_back(op);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
vn = op->getIn(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Duplicate the given PcodeOp so that the outputs have only 1 descendant
|
||||||
|
///
|
||||||
|
/// Run through the descendants of the PcodeOp output and create a duplicate
|
||||||
|
/// of the PcodeOp right before the descendant. We assume the PcodeOp either has
|
||||||
|
/// a single input, or has 2 inputs where the second is a constant.
|
||||||
|
/// The (original) PcodeOp is destroyed.
|
||||||
|
/// \param op is the given PcodeOp to duplicate
|
||||||
|
/// \param data is function to build duplicates in
|
||||||
|
void RulePushPtr::duplicateNeed(PcodeOp *op,Funcdata &data)
|
||||||
|
|
||||||
|
{
|
||||||
|
Varnode *outVn = op->getOut();
|
||||||
|
Varnode *inVn = op->getIn(0);
|
||||||
|
int num = op->numInput();
|
||||||
|
OpCode opc = op->code();
|
||||||
|
list<PcodeOp *>::const_iterator iter = outVn->beginDescend();
|
||||||
|
do {
|
||||||
|
PcodeOp *decOp = *iter;
|
||||||
|
int4 slot = decOp->getSlot(outVn);
|
||||||
|
PcodeOp *newOp = data.newOp(num, op->getAddr()); // Duplicate op associated with original address
|
||||||
|
Varnode *newOut = buildVarnodeOut(outVn, newOp, data); // Result contained in original storage
|
||||||
|
newOut->updateType(outVn->getType(),false,false);
|
||||||
|
data.opSetOpcode(newOp, opc);
|
||||||
|
data.opSetInput(newOp, inVn, 0);
|
||||||
|
if (num > 1)
|
||||||
|
data.opSetInput(newOp, op->getIn(1), 1);
|
||||||
|
data.opSetInput(decOp, newOut, slot);
|
||||||
|
data.opInsertBefore(newOp, decOp);
|
||||||
|
iter = outVn->beginDescend();
|
||||||
|
} while(iter != outVn->endDescend());
|
||||||
|
data.opDestroy(op);
|
||||||
|
}
|
||||||
|
|
||||||
/// \class RulePushPtr
|
/// \class RulePushPtr
|
||||||
/// \brief Push a Varnode with known pointer data-type to the bottom of its additive expression
|
/// \brief Push a Varnode with known pointer data-type to the bottom of its additive expression
|
||||||
///
|
///
|
||||||
@ -6312,47 +6395,51 @@ void RulePushPtr::getOpList(vector<uint4> &oplist) const
|
|||||||
int4 RulePushPtr::applyOp(PcodeOp *op,Funcdata &data)
|
int4 RulePushPtr::applyOp(PcodeOp *op,Funcdata &data)
|
||||||
|
|
||||||
{
|
{
|
||||||
int4 i,j;
|
int4 slot;
|
||||||
PcodeOp *decop,*newop;
|
|
||||||
Varnode *vn;
|
|
||||||
Varnode *vni = (Varnode *)0;
|
Varnode *vni = (Varnode *)0;
|
||||||
const Datatype *ct;
|
|
||||||
|
|
||||||
if (!data.isTypeRecoveryOn()) return 0;
|
if (!data.isTypeRecoveryOn()) return 0;
|
||||||
for(i=0;i<op->numInput();++i) { // Search for pointer type
|
for(slot=0;slot<op->numInput();++slot) { // Search for pointer type
|
||||||
vni = op->getIn(i);
|
vni = op->getIn(slot);
|
||||||
ct = vni->getType();
|
if (vni->getType()->getMetatype() == TYPE_PTR) break;
|
||||||
if (ct->getMetatype() == TYPE_PTR) break;
|
|
||||||
}
|
}
|
||||||
if (i == op->numInput()) return 0;
|
if (slot == op->numInput()) return 0;
|
||||||
if ((i==0)&&(op->getIn(1)->getType()->getMetatype() == TYPE_PTR)) return 0; // Prevent infinite loops
|
|
||||||
|
|
||||||
vn = op->getOut();
|
|
||||||
if ((decop=vn->loneDescend()) == (PcodeOp *)0) return 0;
|
|
||||||
if (decop->code() != CPUI_INT_ADD) return 0;
|
|
||||||
|
|
||||||
j = decop->getSlot(vn);
|
if (RulePtrArith::evaluatePointerExpression(op, slot) != 1) return 0;
|
||||||
if (decop->getIn(1-j)->getType()->getMetatype() == TYPE_PTR) return 0; // Prevent infinite loops
|
Varnode *vn = op->getOut();
|
||||||
|
Varnode *vnadd2 = op->getIn(1-slot);
|
||||||
|
vector<PcodeOp *> duplicateList;
|
||||||
|
if (vn->loneDescend() == (PcodeOp *)0)
|
||||||
|
collectDuplicateNeeds(duplicateList, vnadd2);
|
||||||
|
|
||||||
Varnode *vnadd1 = decop->getIn(1-j);
|
for(;;) {
|
||||||
Varnode *vnadd2 = op->getIn(1-i);
|
list<PcodeOp *>::const_iterator iter = vn->beginDescend();
|
||||||
Varnode *newout;
|
if (iter == vn->endDescend()) break;
|
||||||
|
PcodeOp *decop = *iter;
|
||||||
|
int4 j = decop->getSlot(vn);
|
||||||
|
|
||||||
// vni and vnadd2 are propagated, so they shouldn't be free
|
Varnode *vnadd1 = decop->getIn(1-j);
|
||||||
if (vnadd2->isFree() && (!vnadd2->isConstant())) return 0;
|
Varnode *newout;
|
||||||
if (vni->isFree() && (!vni->isConstant())) return 0;
|
|
||||||
|
|
||||||
newop = data.newOp(2,decop->getAddr());
|
// Create new INT_ADD for the intermediate result that didn't exist in original code.
|
||||||
data.opSetOpcode(newop,CPUI_INT_ADD);
|
// We don't associate it with the address of the original INT_ADD
|
||||||
newout = data.newUniqueOut(vnadd1->getSize(),newop);
|
// We don't preserve the Varnode address of the original INT_ADD
|
||||||
|
PcodeOp *newop = data.newOp(2,decop->getAddr()); // Use the later address
|
||||||
|
data.opSetOpcode(newop,CPUI_INT_ADD);
|
||||||
|
newout = data.newUniqueOut(vnadd1->getSize(),newop); // Use a temporary storage address
|
||||||
|
|
||||||
data.opSetInput(decop,vni,0);
|
data.opSetInput(decop,vni,0);
|
||||||
data.opSetInput(decop,newout,1);
|
data.opSetInput(decop,newout,1);
|
||||||
|
|
||||||
data.opSetInput(newop,vnadd1,0);
|
data.opSetInput(newop,vnadd1,0);
|
||||||
data.opSetInput(newop,vnadd2,1);
|
data.opSetInput(newop,vnadd2,1);
|
||||||
|
|
||||||
data.opInsertBefore(newop,decop);
|
data.opInsertBefore(newop,decop);
|
||||||
|
}
|
||||||
|
if (!vn->isAutoLive())
|
||||||
|
data.opDestroy(op);
|
||||||
|
for(int4 i=0;i<duplicateList.size();++i)
|
||||||
|
duplicateNeed(duplicateList[i], data);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -6648,6 +6735,56 @@ int4 RulePtrsubCharConstant::applyOp(PcodeOp *op,Funcdata &data)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \class RuleExtensionPush
|
||||||
|
/// \brief Duplicate CPUI_INT_ZEXT and CPUI_INT_SEXT operations if the result is used in multiple pointer calculations
|
||||||
|
///
|
||||||
|
/// By making the extension operation part of each pointer calculation (where it is usually an implied cast),
|
||||||
|
/// we can frequently eliminate an explicit variable that would just hold the extension.
|
||||||
|
void RuleExtensionPush::getOpList(vector<uint4> &oplist) const
|
||||||
|
|
||||||
|
{
|
||||||
|
oplist.push_back(CPUI_INT_ZEXT);
|
||||||
|
oplist.push_back(CPUI_INT_SEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
int4 RuleExtensionPush::applyOp(PcodeOp *op,Funcdata &data)
|
||||||
|
|
||||||
|
{
|
||||||
|
Varnode *inVn = op->getIn(0);
|
||||||
|
if (inVn->isConstant()) return 0;
|
||||||
|
if (inVn->isAddrForce()) return 0;
|
||||||
|
if (inVn->isAddrTied()) return 0;
|
||||||
|
Varnode *outVn = op->getOut();
|
||||||
|
if (outVn->isTypeLock() || outVn->isNameLock()) return 0;
|
||||||
|
if (outVn->isAddrForce() || outVn->isAddrTied()) return 0;
|
||||||
|
list<PcodeOp *>::const_iterator iter;
|
||||||
|
int4 addcount = 0; // Number of INT_ADD descendants
|
||||||
|
int4 ptrcount = 0; // Number of PTRADD descendants
|
||||||
|
for(iter=outVn->beginDescend();iter!=outVn->endDescend();++iter) {
|
||||||
|
PcodeOp *decOp = *iter;
|
||||||
|
OpCode opc = decOp->code();
|
||||||
|
if (opc == CPUI_PTRADD) {
|
||||||
|
// This extension will likely be hidden
|
||||||
|
ptrcount += 1;
|
||||||
|
}
|
||||||
|
else if (opc == CPUI_INT_ADD) {
|
||||||
|
PcodeOp *subOp = decOp->getOut()->loneDescend();
|
||||||
|
if (subOp == (PcodeOp *)0 || subOp->code() != CPUI_PTRADD)
|
||||||
|
return 0;
|
||||||
|
addcount += 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((addcount + ptrcount) <= 1) return 0;
|
||||||
|
if (addcount > 0) {
|
||||||
|
if (op->getIn(0)->loneDescend() != (PcodeOp *)0) return 0;
|
||||||
|
}
|
||||||
|
RulePushPtr::duplicateNeed(op, data); // Duplicate the extension to all result descendants
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/// \class RuleSubNormal
|
/// \class RuleSubNormal
|
||||||
/// \brief Pull-back SUBPIECE through INT_RIGHT and INT_SRIGHT
|
/// \brief Pull-back SUBPIECE through INT_RIGHT and INT_SRIGHT
|
||||||
///
|
///
|
||||||
|
@ -1027,7 +1027,6 @@ public:
|
|||||||
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
||||||
};
|
};
|
||||||
class RulePtrArith : public Rule {
|
class RulePtrArith : public Rule {
|
||||||
static bool verifyAddTreeBottom(PcodeOp *op,int4 slot);
|
|
||||||
static bool verifyPreferredPointer(PcodeOp *op,int4 slot);
|
static bool verifyPreferredPointer(PcodeOp *op,int4 slot);
|
||||||
public:
|
public:
|
||||||
RulePtrArith(const string &g) : Rule(g, 0, "ptrarith") {} ///< Constructor
|
RulePtrArith(const string &g) : Rule(g, 0, "ptrarith") {} ///< Constructor
|
||||||
@ -1037,6 +1036,7 @@ public:
|
|||||||
}
|
}
|
||||||
virtual void getOpList(vector<uint4> &oplist) const;
|
virtual void getOpList(vector<uint4> &oplist) const;
|
||||||
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
||||||
|
static int4 evaluatePointerExpression(PcodeOp *op,int4 slot);
|
||||||
};
|
};
|
||||||
class RuleStructOffset0 : public Rule {
|
class RuleStructOffset0 : public Rule {
|
||||||
public:
|
public:
|
||||||
@ -1049,6 +1049,8 @@ public:
|
|||||||
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
||||||
};
|
};
|
||||||
class RulePushPtr : public Rule {
|
class RulePushPtr : public Rule {
|
||||||
|
static Varnode *buildVarnodeOut(Varnode *vn,PcodeOp *op,Funcdata &data);
|
||||||
|
static void collectDuplicateNeeds(vector<PcodeOp *> &reslist,Varnode *vn);
|
||||||
public:
|
public:
|
||||||
RulePushPtr(const string &g) : Rule(g, 0, "pushptr") {} ///< Constructor
|
RulePushPtr(const string &g) : Rule(g, 0, "pushptr") {} ///< Constructor
|
||||||
virtual Rule *clone(const ActionGroupList &grouplist) const {
|
virtual Rule *clone(const ActionGroupList &grouplist) const {
|
||||||
@ -1057,6 +1059,7 @@ public:
|
|||||||
}
|
}
|
||||||
virtual void getOpList(vector<uint4> &oplist) const;
|
virtual void getOpList(vector<uint4> &oplist) const;
|
||||||
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
||||||
|
static void duplicateNeed(PcodeOp *op,Funcdata &data);
|
||||||
};
|
};
|
||||||
class RulePtraddUndo : public Rule {
|
class RulePtraddUndo : public Rule {
|
||||||
public:
|
public:
|
||||||
@ -1136,6 +1139,17 @@ public:
|
|||||||
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RuleExtensionPush : public Rule {
|
||||||
|
public:
|
||||||
|
RuleExtensionPush(const string &g) : Rule( g, 0, "extensionpush") {} ///< Constructor
|
||||||
|
virtual Rule *clone(const ActionGroupList &grouplist) const {
|
||||||
|
if (!grouplist.contains(getGroup())) return (Rule *)0;
|
||||||
|
return new RuleExtensionPush(getGroup());
|
||||||
|
}
|
||||||
|
virtual void getOpList(vector<uint4> &oplist) const;
|
||||||
|
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
||||||
|
};
|
||||||
|
|
||||||
class RuleSubNormal : public Rule {
|
class RuleSubNormal : public Rule {
|
||||||
public:
|
public:
|
||||||
RuleSubNormal(const string &g) : Rule( g, 0, "subnormal") {} ///< Constructor
|
RuleSubNormal(const string &g) : Rule( g, 0, "subnormal") {} ///< Constructor
|
||||||
|
133
Ghidra/Features/Decompiler/src/decompile/datatests/dupptr.xml
Normal file
133
Ghidra/Features/Decompiler/src/decompile/datatests/dupptr.xml
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
<decompilertest>
|
||||||
|
<binaryimage arch="x86:LE:64:default:gcc">
|
||||||
|
<!--
|
||||||
|
Each function has multiple pointer calculations with shared intermediate results.
|
||||||
|
In all cases, the base pointer must be pushed past the intermediate result in
|
||||||
|
order to recover a natural expression.
|
||||||
|
-->
|
||||||
|
<bytechunk space="ram" offset="0x10063a" readonly="true">
|
||||||
|
554889e54889
|
||||||
|
7de88975e48b45e44898488d14c50000
|
||||||
|
0000488b45e84801d0488945f8488b45
|
||||||
|
f8488d5008488d057803000048890248
|
||||||
|
8b45f8488d5010488d056c0300004889
|
||||||
|
02905dc3
|
||||||
|
</bytechunk>
|
||||||
|
<bytechunk space="ram" offset="0x1006ba" readonly="true">
|
||||||
|
554889e54881
|
||||||
|
eca800000089bd5cffffff488d8560ff
|
||||||
|
ffff4889c7e8aaffffff488d8560ffff
|
||||||
|
ff8b955cffffff4863d248c1e2024801
|
||||||
|
d0488945f8488b45f84883c008488945
|
||||||
|
f0488b45f08b00c1f80383e00f89c248
|
||||||
|
8b45f0891090c9c3
|
||||||
|
</bytechunk>
|
||||||
|
<bytechunk space="ram" offset="0x100718" readonly="true">
|
||||||
|
554889e54883ec20
|
||||||
|
48897de88975e4488b45e84889c7e851
|
||||||
|
ffffff8b45e44898488d148500000000
|
||||||
|
488b45e84801d0488945f8488b45f848
|
||||||
|
83c008488945f0488b45f08b00c1f803
|
||||||
|
83e00f89c2488b45f0891090c9c3
|
||||||
|
</bytechunk>
|
||||||
|
<bytechunk space="ram" offset="0x10076e" readonly="true">
|
||||||
|
5548
|
||||||
|
89e54881ec7805000089bd8cfaffff48
|
||||||
|
8d8590faffff4889c7e8f6feffff488d
|
||||||
|
8590faffff4883c024488945f88b858c
|
||||||
|
faffff4898488945f0488b55f04889d0
|
||||||
|
48c1e0044801d048c1e0034889c2488b
|
||||||
|
45f84801d0488945e8488b45f04883c0
|
||||||
|
014889c24889d048c1e0044801d048c1
|
||||||
|
e0034889c2488b45f84801d0488945e0
|
||||||
|
488b45e88b008d5025488b45e0891090
|
||||||
|
c9c3
|
||||||
|
</bytechunk>
|
||||||
|
<bytechunk space="ram" offset="0x100802" readonly="true">
|
||||||
|
554889e548897dd88975d48b45d4
|
||||||
|
4898488d148500000000488b45d84801
|
||||||
|
d0488945f8488b45f84883c008488945
|
||||||
|
f0488b45f84883c048488945e8488b45
|
||||||
|
f0c70007000000488b45e8c7006f0000
|
||||||
|
00905dc3
|
||||||
|
</bytechunk>
|
||||||
|
<bytechunk space="ram" offset="0x100854" readonly="true">
|
||||||
|
554889e548897dd88975d48b
|
||||||
|
45d44863d04889d04801c04801d048c1
|
||||||
|
e0024889c2488b45d84801d04883c004
|
||||||
|
488945f8488b45f84883e880488945f0
|
||||||
|
488b45f84883c008488945e8488b45f0
|
||||||
|
c70014000000488b45e8c7001e000000
|
||||||
|
905dc3
|
||||||
|
</bytechunk>
|
||||||
|
<bytechunk space="ram" offset="0x1008b3" readonly="true">
|
||||||
|
554889e548897dd88975d4488b
|
||||||
|
45d84883c01c488945f8488b45f8488d
|
||||||
|
50088b45d4489848c1e00a4801d04889
|
||||||
|
45f0488b45f8488d50088b45d483c001
|
||||||
|
489848c1e00a4801d0488945e8488b45
|
||||||
|
e88b008d50fd488b45f08910905dc3
|
||||||
|
</bytechunk>
|
||||||
|
<bytechunk space="ram" offset="0x1009e4" readonly="true">
|
||||||
|
48656c6c6f00476f6f6462796500
|
||||||
|
</bytechunk>
|
||||||
|
<symbol space="ram" offset="0x10063a" name="argv_test"/>
|
||||||
|
<symbol space="ram" offset="0x100684" name="initstruct"/>
|
||||||
|
<symbol space="ram" offset="0x1006a4" name="inithierarchy"/>
|
||||||
|
<symbol space="ram" offset="0x1006af" name="initarrayarray"/>
|
||||||
|
<symbol space="ram" offset="0x1006ba" name="loadstore_fieldarray"/>
|
||||||
|
<symbol space="ram" offset="0x100718" name="loadstore_ptrfieldarray"/>
|
||||||
|
<symbol space="ram" offset="0x10076e" name="doublearray_stack"/>
|
||||||
|
<symbol space="ram" offset="0x100802" name="sameindex"/>
|
||||||
|
<symbol space="ram" offset="0x100854" name="sameindex_samefield"/>
|
||||||
|
<symbol space="ram" offset="0x1008b3" name="twodim_array"/>
|
||||||
|
</binaryimage>
|
||||||
|
<script>
|
||||||
|
<com>parse line struct arraystruct { int4 a; int4 b; int4 arr1[16]; int4 arr2[16]; };</com>
|
||||||
|
<com>parse line struct substruct { int4 c; int4 d; int4 e; };</com>
|
||||||
|
<com>parse line struct hierarchy { int4 a; int4 b; substruct arr1[10]; substruct arr2[10]; };</com>
|
||||||
|
<com>parse line struct arrayarray { int4 a; int4 b; int4 arr[8][256]; };</com>
|
||||||
|
<com>parse line extern void initstruct(arraystruct *ptr);</com>
|
||||||
|
<com>parse line extern void inithierarchy(hierarchy *ptr);</com>
|
||||||
|
<com>parse line extern void initarrayarray(arrayarray *ptr);</com>
|
||||||
|
<com>parse line extern void argv_test(char **argv,int4 a);</com>
|
||||||
|
<com>parse line extern void loadstore_fieldarray(int4 a);</com>
|
||||||
|
<com>parse line extern void loadstore_ptrfieldarray(arraystruct *ptr,int4 a);</com>
|
||||||
|
<com>parse line extern void doublearray_stack(int4 a);</com>
|
||||||
|
<com>parse line extern void sameindex(arraystruct *ptr,int4 a);</com>
|
||||||
|
<com>parse line extern void sameindex_samefield(hierarchy *ptr,int4 a);</com>
|
||||||
|
<com>parse line extern void twodim_array(arrayarray *ptr,int4 a);</com>
|
||||||
|
<com>lo fu argv_test</com>
|
||||||
|
<com>dec</com>
|
||||||
|
<com>print C</com>
|
||||||
|
<com>lo fu loadstore_fieldarray</com>
|
||||||
|
<com>dec</com>
|
||||||
|
<com>print C</com>
|
||||||
|
<com>lo fu loadstore_ptrfieldarray</com>
|
||||||
|
<com>dec</com>
|
||||||
|
<com>print C</com>
|
||||||
|
<com>lo fu doublearray_stack</com>
|
||||||
|
<com>dec</com>
|
||||||
|
<com>print C</com>
|
||||||
|
<com>lo fu sameindex</com>
|
||||||
|
<com>dec</com>
|
||||||
|
<com>print C</com>
|
||||||
|
<com>lo fu sameindex_samefield</com>
|
||||||
|
<com>dec</com>
|
||||||
|
<com>print C</com>
|
||||||
|
<com>lo fu twodim_array</com>
|
||||||
|
<com>dec</com>
|
||||||
|
<com>print C</com>
|
||||||
|
<com>quit</com>
|
||||||
|
</script>
|
||||||
|
<stringmatch name="Intermediate pointers #1" min="1" max="1">argv\[\(int8\)a \+ 1\] = "Hello";</stringmatch>
|
||||||
|
<stringmatch name="Intermediate pointers #2" min="1" max="1">argv\[\(int8\)a \+ 2\] = "Goodbye";</stringmatch>
|
||||||
|
<stringmatch name="Intermediate pointers #3" min="1" max="1">aStack168\.arr1\[a\] = aStack168\.arr1\[a\] >> 3 & 0xf;</stringmatch>
|
||||||
|
<stringmatch name="Intermediate pointers #4" min="1" max="1">ptr->arr1\[a\] = ptr->arr1\[a\] >> 3 & 0xf;</stringmatch>
|
||||||
|
<stringmatch name="Intermediate pointers #5" min="1" max="1">aaStack1400\[\(int8\)a \+ 1\]\.arr1\[7\] = aaStack1400\[a\]\.arr1\[7\] \+ 0x25;</stringmatch>
|
||||||
|
<stringmatch name="Intermediate pointers #6" min="1" max="1">ptr->arr1\[a\] = 7;</stringmatch>
|
||||||
|
<stringmatch name="Intermediate pointers #7" min="1" max="1">ptr->arr2\[a\] = 0x6f;</stringmatch>
|
||||||
|
<stringmatch name="Intermediate pointers #8" min="1" max="1">ptr->arr1\[a\]\.d = 0x1e;</stringmatch>
|
||||||
|
<stringmatch name="Intermediate pointers #9" min="1" max="1">ptr->arr2\[a\]\.d = 0x14;</stringmatch>
|
||||||
|
<stringmatch name="Intermediate pointers #10" min="1" max="1">ptr->arr\[a\]\[7\] = ptr->arr\[a \+ 1\]\[7\] \+ -3;</stringmatch>
|
||||||
|
</decompilertest>
|
Loading…
Reference in New Issue
Block a user