mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 02:09:44 +02:00
GP-2957 Sub-flow through INT_DIV and INT_REM
This commit is contained in:
parent
16388dc261
commit
8847d2a6b9
4 changed files with 65 additions and 26 deletions
|
@ -4439,28 +4439,23 @@ bool RuleSubCommute::cancelExtensions(PcodeOp *longform,PcodeOp *subOp,Varnode *
|
|||
int4 RuleSubCommute::applyOp(PcodeOp *op,Funcdata &data)
|
||||
|
||||
{
|
||||
Varnode *base,*vn,*newvn,*outvn;
|
||||
PcodeOp *longform,*newsub,*prevop;
|
||||
int4 i,j,offset,insize;
|
||||
|
||||
base = op->getIn(0);
|
||||
Varnode *base = op->getIn(0);
|
||||
if (!base->isWritten()) return 0;
|
||||
offset = op->getIn(1)->getOffset();
|
||||
outvn = op->getOut();
|
||||
int4 offset = op->getIn(1)->getOffset();
|
||||
Varnode *outvn = op->getOut();
|
||||
if (outvn->isPrecisLo()||outvn->isPrecisHi()) return 0;
|
||||
insize = base->getSize();
|
||||
longform = base->getDef();
|
||||
j = -1;
|
||||
int4 insize = base->getSize();
|
||||
PcodeOp *longform = base->getDef();
|
||||
int4 j = -1;
|
||||
switch( longform->code() ) { // Determine if this op commutes with SUBPIECE
|
||||
// case CPUI_COPY:
|
||||
case CPUI_INT_LEFT:
|
||||
j = 1; // Special processing for shift amount param
|
||||
if (offset != 0) return 0;
|
||||
if (!longform->getIn(0)->isWritten()) return 0;
|
||||
prevop = longform->getIn(0)->getDef();
|
||||
if (prevop->code()==CPUI_INT_ZEXT) {
|
||||
}
|
||||
else if (prevop->code()==CPUI_PIECE) {
|
||||
if (longform->getIn(0)->isWritten()) {
|
||||
OpCode opc = longform->getIn(0)->getDef()->code();
|
||||
if (opc != CPUI_INT_ZEXT && opc != CPUI_PIECE)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
@ -4558,17 +4553,24 @@ int4 RuleSubCommute::applyOp(PcodeOp *op,Funcdata &data)
|
|||
}
|
||||
}
|
||||
|
||||
for(i=0;i<longform->numInput();++i) {
|
||||
vn = longform->getIn(i);
|
||||
Varnode *lastIn = (Varnode *)0;
|
||||
Varnode *newVn = (Varnode *)0;
|
||||
for(int4 i=0;i<longform->numInput();++i) {
|
||||
Varnode *vn = longform->getIn(i);
|
||||
if (i!=j) {
|
||||
newsub = data.newOp(2,op->getAddr()); // Commuted SUBPIECE op
|
||||
data.opSetOpcode(newsub,CPUI_SUBPIECE);
|
||||
newvn = data.newUniqueOut(outvn->getSize(),newsub); // New varnode is subpiece
|
||||
data.opSetInput(longform,newvn,i);
|
||||
data.opSetInput(newsub,vn,0); // of old varnode
|
||||
data.opSetInput(newsub,data.newConstant(4,offset),1);
|
||||
data.opInsertBefore(newsub,longform);
|
||||
if (lastIn != vn || newVn == (Varnode *)0) { // Don't duplicate the SUBPIECE if inputs are the same
|
||||
PcodeOp *newsub = data.newOp(2,op->getAddr()); // Commuted SUBPIECE op
|
||||
data.opSetOpcode(newsub,CPUI_SUBPIECE);
|
||||
newVn = data.newUniqueOut(outvn->getSize(),newsub); // New varnode is SUBPIECE of old varnode
|
||||
data.opSetInput(longform,newVn,i);
|
||||
data.opSetInput(newsub,vn,0); // vn may be free, so set as input after setting newVn
|
||||
data.opSetInput(newsub,data.newConstant(4,offset),1);
|
||||
data.opInsertBefore(newsub,longform);
|
||||
}
|
||||
else
|
||||
data.opSetInput(longform,newVn,i);
|
||||
}
|
||||
lastIn = vn;
|
||||
}
|
||||
data.opSetOutput(longform,outvn);
|
||||
data.opDestroy(op); // Get rid of old SUBPIECE
|
||||
|
|
|
@ -443,6 +443,16 @@ bool SubvariableFlow::traceForward(ReplaceVarnode *rvn)
|
|||
if (!createLink(rop,rvn->mask<<sa,-1,outvn)) return false;
|
||||
hcount += 1;
|
||||
break;
|
||||
case CPUI_INT_DIV:
|
||||
case CPUI_INT_REM:
|
||||
if ((rvn->mask & 1)==0) return false; // Logical value must be least sig bits
|
||||
if ((bitsize & 7)!=0) return false; // Must be a whole number of bytes
|
||||
if (!op->getIn(0)->isZeroExtended(flowsize)) return false;
|
||||
if (!op->getIn(1)->isZeroExtended(flowsize)) return false;
|
||||
rop = createOpDown(op->code(),2,op,rvn,slot);
|
||||
if (!createLink(rop,rvn->mask,-1,outvn)) return false;
|
||||
hcount += 1;
|
||||
break;
|
||||
case CPUI_INT_ADD:
|
||||
if ((rvn->mask & 1)==0)
|
||||
return false; // Cannot account for carry
|
||||
|
@ -768,6 +778,16 @@ bool SubvariableFlow::traceBackward(ReplaceVarnode *rvn)
|
|||
if (!createLink(rop,rvn->mask,1,op->getIn(1))) return false;
|
||||
}
|
||||
return true;
|
||||
case CPUI_INT_DIV:
|
||||
case CPUI_INT_REM:
|
||||
if ((rvn->mask & 1) == 0) return false;
|
||||
if ((bitsize & 7)!=0) return false; // Must be a whole number of bytes
|
||||
if (!op->getIn(0)->isZeroExtended(flowsize)) return false;
|
||||
if (!op->getIn(1)->isZeroExtended(flowsize)) return false;
|
||||
rop = createOp(op->code(),2,rvn);
|
||||
if (!createLink(rop,rvn->mask,0,op->getIn(0))) return false;
|
||||
if (!createLink(rop,rvn->mask,1,op->getIn(1))) return false;
|
||||
return true;
|
||||
case CPUI_SUBPIECE:
|
||||
sa = (int4)op->getIn(1)->getOffset() * 8;
|
||||
newmask = rvn->mask << sa;
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -940,6 +940,22 @@ bool Varnode::isBooleanValue(bool useAnnotation) const
|
|||
return false;
|
||||
}
|
||||
|
||||
/// If we can prove that the upper bits of \b this are zero, return \b true.
|
||||
/// \param baseSize is the maximum number of least significant bytes that are allowed to be non-zero
|
||||
/// \return \b true if all the most significant bytes are zero
|
||||
bool Varnode::isZeroExtended(int4 baseSize) const
|
||||
|
||||
{
|
||||
if (baseSize >= size) return false;
|
||||
if (size > sizeof(uintb)) {
|
||||
if (!isWritten()) return false;
|
||||
if (def->code() != CPUI_INT_ZEXT) return false;
|
||||
if (def->getIn(0)->getSize() > baseSize) return false;
|
||||
return true;
|
||||
}
|
||||
uintb mask = nzm >> 8*baseSize;
|
||||
return (mask == 0);
|
||||
}
|
||||
|
||||
/// Make a local determination if \b this and \b op2 hold the same value. We check if
|
||||
/// there is a common ancester for which both \b this and \b op2 are created from a direct
|
||||
|
|
|
@ -340,6 +340,7 @@ public:
|
|||
void copySymbolIfValid(const Varnode *vn); ///< Copy symbol info from \b vn if constant value matches
|
||||
Datatype *getLocalType(bool &blockup) const; ///< Calculate type of Varnode based on local information
|
||||
bool isBooleanValue(bool useAnnotation) const; ///< Does \b this Varnode hold a formal boolean value
|
||||
bool isZeroExtended(int4 baseSize) const; ///< Is \b this zero extended from something of the given size
|
||||
bool copyShadow(const Varnode *op2) const; ///< Are \b this and \b op2 copied from the same source?
|
||||
bool findSubpieceShadow(int4 leastByte,const Varnode *whole,int4 recurse) const;
|
||||
bool findPieceShadow(int4 leastByte,const Varnode *piece) const;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue