Merge remote-tracking branch 'origin/caheckman_MultiplyCorners'

This commit is contained in:
ghidravore 2020-09-18 15:40:18 -04:00
commit d5a5f80d29
7 changed files with 222 additions and 50 deletions

View file

@ -5018,6 +5018,7 @@ void ActionDatabase::universalAction(Architecture *conf)
actprop->addRule( new RulePiece2Zext("analysis") );
actprop->addRule( new RulePiece2Sext("analysis") );
actprop->addRule( new RulePopcountBoolXor("analysis") );
actprop->addRule( new RuleXorSwap("analysis") );
actprop->addRule( new RuleSubvarAnd("subvar") );
actprop->addRule( new RuleSubvarSubpiece("subvar") );
actprop->addRule( new RuleSplitFlow("subvar") );

View file

@ -529,7 +529,22 @@ uintb PcodeOp::getNZMaskLocal(bool cliploop) const
break;
case CPUI_SUBPIECE:
resmask = getIn(0)->getNZMask();
resmask >>= 8*getIn(1)->getOffset();
sz1 = (int4)getIn(1)->getOffset();
if ((int4)getIn(0)->getSize() <= sizeof(uintb)) {
if (sz1 < sizeof(uintb))
resmask >>= 8*sz1;
else
resmask = 0;
}
else { // Extended precision
if (sz1 < sizeof(uintb)) {
resmask >>= 8*sz1;
if (sz1 > 0)
resmask |= fullmask << (8*(sizeof(uintb)-sz1));
}
else
resmask = fullmask;
}
resmask &= fullmask;
break;
case CPUI_PIECE:
@ -540,11 +555,11 @@ uintb PcodeOp::getNZMaskLocal(bool cliploop) const
case CPUI_INT_MULT:
val = getIn(0)->getNZMask();
resmask = getIn(1)->getNZMask();
sz1 = mostsigbit_set(val);
sz1 = (size > sizeof(uintb)) ? 8*size-1 : mostsigbit_set(val);
if (sz1 == -1)
resmask = 0;
else {
sz2 = mostsigbit_set(resmask);
sz2 = (size > sizeof(uintb)) ? 8*size-1 : mostsigbit_set(resmask);
if (sz2 == -1)
resmask = 0;
else {

View file

@ -507,7 +507,7 @@ uintb OpBehaviorIntSrem::evaluateBinary(int4 sizeout,int4 sizein,uintb in1,uintb
intb mod = in2;
sign_extend(val,8*sizein-1); // Convert inputs to signed values
sign_extend(mod,8*sizein-1);
intb sres = in1 % in2; // Do the remainder
intb sres = val % mod; // Do the remainder
zero_extend(sres,8*sizeout-1); // Convert back to unsigned
return (uintb)sres;
}

View file

@ -6970,7 +6970,12 @@ Varnode *RuleDivOpt::findForm(PcodeOp *op,int4 &n,uintb &y,int4 &xsize,OpCode &e
if (curOp->code() != CPUI_INT_MULT) return (Varnode *)0; // There MUST be an INT_MULT
Varnode *inVn = curOp->getIn(0);
if (!inVn->isWritten()) return (Varnode *)0;
if (curOp->getIn(1)->isConstantExtended(y) < 0) return (Varnode *)0; // There MUST be a constant
if (inVn->isConstantExtended(y) >= 0) {
inVn = curOp->getIn(1);
if (!inVn->isWritten()) return (Varnode *)0;
}
else if (curOp->getIn(1)->isConstantExtended(y) < 0)
return (Varnode *)0; // There MUST be a constant
Varnode *resVn;
PcodeOp *extOp = inVn->getDef();
@ -7062,29 +7067,81 @@ uintb RuleDivOpt::calcDivisor(uintb n,uint8 y,int4 xsize)
/// - `V >> 0x1f`
/// - `V s>> 0x1f`
///
/// Allow for the value to be COPYed around.
/// \param firstVn is the first given Varnode
/// \param replaceVn is the Varnode to replace it with in each extraction
/// \param data is the function holding the Varnodes
void RuleDivOpt::moveSignBitExtraction(Varnode *firstVn,Varnode *replaceVn,Funcdata &data)
{
list<PcodeOp *>::const_iterator iter = firstVn->beginDescend();
while(iter!=firstVn->endDescend()) {
PcodeOp *op = *iter;
++iter; // Increment before modifying the op
OpCode opc = op->code();
if (opc == CPUI_INT_RIGHT || opc == CPUI_INT_SRIGHT) {
Varnode *constVn = op->getIn(1);
if (constVn->isConstant()) {
int4 sa = firstVn->getSize() * 8 - 1;
if (sa == (int4)constVn->getOffset()) {
data.opSetInput(op,replaceVn,0);
vector<Varnode *> testList;
testList.push_back(firstVn);
if (firstVn->isWritten()) {
PcodeOp *op = firstVn->getDef();
if (op->code() == CPUI_INT_SRIGHT) {
// Same sign bit could be extracted from previous shifted version
testList.push_back(op->getIn(0));
}
}
for(int4 i=0;i<testList.size();++i) {
Varnode *vn = testList[i];
list<PcodeOp *>::const_iterator iter = vn->beginDescend();
while(iter!=vn->endDescend()) {
PcodeOp *op = *iter;
++iter; // Increment before modifying the op
OpCode opc = op->code();
if (opc == CPUI_INT_RIGHT || opc == CPUI_INT_SRIGHT) {
Varnode *constVn = op->getIn(1);
if (constVn->isWritten()) {
PcodeOp *constOp = constVn->getDef();
if (constOp->code() == CPUI_COPY)
constVn = constOp->getIn(0);
else if (constOp->code() == CPUI_INT_AND) {
constVn = constOp->getIn(0);
Varnode *otherVn = constOp->getIn(1);
if (!otherVn->isConstant()) continue;
if (constVn->getOffset() != (constVn->getOffset() & otherVn->getOffset())) continue;
}
}
if (constVn->isConstant()) {
int4 sa = firstVn->getSize() * 8 - 1;
if (sa == (int4)constVn->getOffset()) {
data.opSetInput(op,replaceVn,0);
}
}
}
else if (opc == CPUI_COPY) {
testList.push_back(op->getOut());
}
}
}
}
/// A form ending in a SUBPIECE, may be contained in a working form ending at
/// the SUBPIECE followed by INT_SRIGHT. The containing form would supersede.
/// \param op is the root of the form to check
/// \return \b true if it is (possibly) contained in a superseding form
bool RuleDivOpt::checkFormOverlap(PcodeOp *op)
{
if (op->code() != CPUI_SUBPIECE) return false;
Varnode *vn = op->getOut();
list<PcodeOp *>::const_iterator iter;
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
PcodeOp *superOp = *iter;
OpCode opc = superOp->code();
if (opc != CPUI_INT_RIGHT && opc != CPUI_INT_SRIGHT) continue;
Varnode *cvn = superOp->getIn(1);
if (!cvn->isConstant()) return true; // Might be a form where constant has propagated yet
int4 n,xsize;
uintb y;
OpCode extopc;
Varnode *inVn = findForm(superOp, n, y, xsize, extopc);
if (inVn != (Varnode *)0) return true;
}
return false;
}
/// \class RuleDivOpt
/// \brief Convert INT_MULT and shift forms into INT_DIV or INT_SDIV
///
@ -7107,6 +7164,7 @@ int4 RuleDivOpt::applyOp(PcodeOp *op,Funcdata &data)
OpCode extOpc;
Varnode *inVn = findForm(op,n,y,xsize,extOpc);
if (inVn == (Varnode *)0) return 0;
if (checkFormOverlap(op)) return 0;
if (extOpc == CPUI_INT_SEXT)
xsize -= 1; // one less bit for signed, because of signbit
uintb divisor = calcDivisor(n,y,xsize);
@ -9023,3 +9081,35 @@ int4 RulePiecePathology::applyOp(PcodeOp *op,Funcdata &data)
return tracePathologyForward(op, data);
}
void RuleXorSwap::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_XOR);
}
int4 RuleXorSwap::applyOp(PcodeOp *op,Funcdata &data)
{
for(int4 i=0;i<2;++i) {
Varnode *vn = op->getIn(i);
if (!vn->isWritten()) continue;
PcodeOp *op2 = vn->getDef();
if (op2->code() != CPUI_INT_XOR) continue;
Varnode *othervn = op->getIn(1-i);
Varnode *vn0 = op2->getIn(0);
Varnode *vn1 = op2->getIn(1);
if (othervn == vn0 && !vn1->isFree()) {
data.opRemoveInput(op, 1);
data.opSetOpcode(op, CPUI_COPY);
data.opSetInput(op, vn1, 0);
return 1;
}
else if (othervn == vn1 && !vn0->isFree()) {
data.opRemoveInput(op, 1);
data.opSetOpcode(op, CPUI_COPY);
data.opSetInput(op, vn0, 0);
return 1;
}
}
return 0;
}

View file

@ -1194,6 +1194,7 @@ public:
class RuleDivOpt : public Rule {
static uintb calcDivisor(uintb n,uint8 y,int4 xsize); ///< Calculate the divisor
static void moveSignBitExtraction(Varnode *firstVn,Varnode *replaceVn,Funcdata &data);
static bool checkFormOverlap(PcodeOp *op); ///< If form rooted at given PcodeOp is superseded by an overlapping form
public:
RuleDivOpt(const string &g) : Rule( g, 0, "divopt") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
@ -1476,4 +1477,16 @@ public:
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleXorSwap : public Rule {
public:
RuleXorSwap(const string &g) : Rule(g,0,"xorswap") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleXorSwap(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
#endif

View file

@ -577,12 +577,17 @@ Datatype *TypeOpCall::getInputLocal(const PcodeOp *op,int4 slot) const
// Its false to assume that the parameter symbol corresponds
// to the varnode in the same slot, but this is easiest until
// we get giant sized parameters working properly
if ((fc->numParams() == op->numInput()-1)||(fc->isDotdotdot())) {
ProtoParameter *param = fc->getParam(slot-1);
if ((param != (ProtoParameter *)0)&&(param->isTypeLocked())) {
ProtoParameter *param = fc->getParam(slot - 1);
if (param != (ProtoParameter*) 0) {
if (param->isTypeLocked()) {
ct = param->getType();
if ((ct->getMetatype() != TYPE_VOID)&&
(ct->getSize() <= op->getIn(slot)->getSize())) // parameter may not match varnode
if ((ct->getMetatype() != TYPE_VOID) && (ct->getSize() <= op->getIn(slot)->getSize())) // parameter may not match varnode
return ct;
}
else if (param->isThisPointer()) {
// Known "this" pointer is effectively typelocked even if the prototype as a whole isn't
ct = param->getType();
if (ct->getMetatype() == TYPE_PTR && ((TypePointer*) ct)->getPtrTo()->getMetatype() == TYPE_STRUCT)
return ct;
}
}
@ -630,10 +635,17 @@ Datatype *TypeOpCallind::getInputLocal(const PcodeOp *op,int4 slot) const
if (fc == (const FuncCallSpecs *)0)
return TypeOp::getInputLocal(op,slot);
ProtoParameter *param = fc->getParam(slot-1);
if ((param != (ProtoParameter *)0)&&(param->isTypeLocked())) {
ct = param->getType();
if (ct->getMetatype() != TYPE_VOID)
return ct;
if (param != (ProtoParameter *)0) {
if (param->isTypeLocked()) {
ct = param->getType();
if (ct->getMetatype() != TYPE_VOID)
return ct;
}
else if (param->isThisPointer()) {
ct = param->getType();
if (ct->getMetatype() == TYPE_PTR && ((TypePointer *)ct)->getPtrTo()->getMetatype() == TYPE_STRUCT)
return ct;
}
}
return TypeOp::getInputLocal(op,slot);
}

View file

@ -38,24 +38,37 @@ public class VarnodeBank {
/*
* Compare objects by location, size, then definition
*/
@Override
public int compare(VarnodeAST v1, VarnodeAST v2) {
int cmp = v1.getAddress().compareTo(v2.getAddress());
if (cmp!=0)
if (cmp!=0) {
return cmp;
if (v1.getSize() != v2.getSize())
}
if (v1.getSize() != v2.getSize()) {
return (v1.getSize() < v2.getSize() ? -1 : 1);
}
if (v1.isInput()) {
if (v2.isInput()) return 0;
if (v2.isInput()) {
return 0;
}
return -1;
}
if (v2.isInput()) return 1;
if (v2.isInput()) {
return 1;
}
if (v1.getDef() != null) {
if (v2.getDef()==null) return -1;
if (v2.getDef()==null) {
return -1;
}
return v1.getDef().getSeqnum().compareTo(v2.getDef().getSeqnum());
}
if (v2.getDef()!=null) return 1;
if (v2.getDef()!=null) {
return 1;
}
// Reaching this point guarantees both Varnodes are free
if (v1.getUniqueId() == v2.getUniqueId()) return 0;
if (v1.getUniqueId() == v2.getUniqueId()) {
return 0;
}
return (v1.getUniqueId()<v2.getUniqueId() ? -1 : 1);
}
}
@ -65,23 +78,37 @@ public class VarnodeBank {
/*
* Compare by definition then location and size
*/
@Override
public int compare(VarnodeAST v1, VarnodeAST v2) {
int comp;
if (v1.isInput()) {
if (!v2.isInput()) return -1;
if (!v2.isInput()) {
return -1;
}
}
else if (v1.getDef() != null) {
if (v2.isInput()) return 1;
if (v2.isFree()) return -1;
if (v2.isInput()) {
return 1;
}
if (v2.isFree()) {
return -1;
}
comp = v1.getDef().getSeqnum().compareTo(v2.getDef().getSeqnum());
if (comp != 0) return comp;
if (comp != 0) {
return comp;
}
}
comp = v1.getAddress().compareTo(v2.getAddress());
if (comp != 0) return comp;
if (v1.getSize() != v2.getSize())
if (comp != 0) {
return comp;
}
if (v1.getSize() != v2.getSize()) {
return (v1.getSize() < v2.getSize() ? -1 : 1);
}
if (v1.isFree()) { // Both Varnodes must be free, compare uniqId
if (v1.getUniqueId()==v2.getUniqueId()) return 0;
if (v1.getUniqueId()==v2.getUniqueId()) {
return 0;
}
return (v1.getUniqueId() < v2.getUniqueId() ? -1 : 1);
}
return 0;
@ -149,8 +176,12 @@ public class VarnodeBank {
}
public Varnode setInput(Varnode vn) {
if (!vn.isFree()) return null;
if (vn.isConstant()) return null;
if (!vn.isFree()) {
return null;
}
if (vn.isConstant()) {
return null;
}
VarnodeAST vn1 = (VarnodeAST)vn;
locTree.remove(vn1);
@ -160,8 +191,12 @@ public class VarnodeBank {
}
public Varnode setDef(Varnode vn,PcodeOp op) {
if (!vn.isFree()) return null;
if (vn.isConstant()) return null;
if (!vn.isFree()) {
return null;
}
if (vn.isConstant()) {
return null;
}
VarnodeAST vn1 = (VarnodeAST)vn;
locTree.remove(vn1);
@ -177,9 +212,8 @@ public class VarnodeBank {
public Iterator<VarnodeAST> locRange(AddressSpace spaceid) {
VarnodeAST searchvn1 = new VarnodeAST(spaceid.getAddress(0),0,0);
searchvn1.setInput(true);
VarnodeAST searchvn2 = new VarnodeAST(spaceid.getAddress(Long.MAX_VALUE),0,0);
searchvn2.setInput(true);
return locTree.subSet(searchvn1,searchvn2).iterator();
VarnodeAST searchvn2 = new VarnodeAST(spaceid.getMaxAddress(), Integer.MAX_VALUE, 0);
return locTree.subSet(searchvn1, searchvn2).iterator();
}
public Iterator<VarnodeAST> locRange(Address addr) {
@ -206,11 +240,17 @@ public class VarnodeBank {
Iterator<VarnodeAST> iter = locTree.tailSet(searchvn).iterator();
for(;iter.hasNext();) {
VarnodeAST vn = iter.next();
if (vn.getSize()!=sz) break;
if (!vn.getAddress().equals(addr)) break;
if (vn.getSize()!=sz) {
break;
}
if (!vn.getAddress().equals(addr)) {
break;
}
PcodeOp op2 = vn.getDef();
if ((op2!=null)&&(op2.getSeqnum().getTarget().equals(pc))) {
if ((uniq==-1)||(op2.getSeqnum().getTime()==uniq)) return vn;
if ((uniq==-1)||(op2.getSeqnum().getTime()==uniq)) {
return vn;
}
}
}
return null;
@ -222,8 +262,9 @@ public class VarnodeBank {
Iterator<VarnodeAST> iter = locTree.tailSet(searchvn).iterator();
if (iter.hasNext()) {
VarnodeAST vn = iter.next();
if (vn.isInput() && (vn.getSize()==sz) && vn.getAddress().equals(addr))
if (vn.isInput() && (vn.getSize()==sz) && vn.getAddress().equals(addr)) {
return vn;
}
}
return null;
}