GP-4214 Allow INT_ADD in the iblock

This commit is contained in:
caheckman 2025-09-02 18:17:49 +00:00
parent 48a7542e47
commit ce09332fcd
4 changed files with 45 additions and 20 deletions

View file

@ -122,7 +122,12 @@ bool ConditionalExecution::testOpRead(Varnode *vn,PcodeOp *op)
{ {
if (op->getParent() == iblock) return true; if (op->getParent() == iblock) return true;
PcodeOp *writeOp = vn->getDef(); PcodeOp *writeOp = vn->getDef();
if (writeOp->code() == CPUI_COPY || writeOp->code() == CPUI_SUBPIECE) { OpCode opc = writeOp->code();
if (opc == CPUI_COPY || opc == CPUI_SUBPIECE || opc == CPUI_INT_ADD || opc == CPUI_PTRSUB) {
if (opc == CPUI_INT_ADD || opc == CPUI_PTRSUB) {
if (!writeOp->getIn(1)->isConstant())
return false;
}
Varnode *invn = writeOp->getIn(0); Varnode *invn = writeOp->getIn(0);
if (invn->isWritten()) { if (invn->isWritten()) {
PcodeOp *upop = invn->getDef(); PcodeOp *upop = invn->getDef();
@ -146,18 +151,19 @@ Varnode *ConditionalExecution::findPullback(int4 inbranch)
return pullback[inbranch]; return pullback[inbranch];
} }
/// Create a duplicate SUBPIECE outside the iblock. If the SUBPIECE input is defined by a MULTIEQUAL in the iblock, /// Create a duplicate PcodeOp outside the iblock. The first input to the PcodeOp can
/// the duplicate's input will be selected from the MULTIEQUAL input. /// be defined by a MULTIEQUAL in the iblock, in which case the duplicate's input will be
/// \param subOp is the SUBPIECE in the iblock being replaced /// selected from the MULTIEQUAL input. Any other inputs must be constants.
/// \param op is the PcodeOp in the iblock being replaced
/// \param inbranch is the direction to pullback from /// \param inbranch is the direction to pullback from
/// \return the output Varnode of the new SUBPIECE /// \return the output Varnode of the new op
Varnode *ConditionalExecution::pullbackSubpiece(PcodeOp *subOp,int4 inbranch) Varnode *ConditionalExecution::pullbackOp(PcodeOp *op,int4 inbranch)
{ {
Varnode *invn = findPullback(inbranch); // Look for pullback constructed for a previous read Varnode *invn = findPullback(inbranch); // Look for pullback constructed for a previous read
if (invn != (Varnode *)0) if (invn != (Varnode *)0)
return invn; return invn;
invn = subOp->getIn(0); invn = op->getIn(0);
BlockBasic *bl; BlockBasic *bl;
if (invn->isWritten()) { if (invn->isWritten()) {
PcodeOp *defOp = invn->getDef(); PcodeOp *defOp = invn->getDef();
@ -166,17 +172,18 @@ Varnode *ConditionalExecution::pullbackSubpiece(PcodeOp *subOp,int4 inbranch)
invn = defOp->getIn(inbranch); // defOp must by MULTIEQUAL invn = defOp->getIn(inbranch); // defOp must by MULTIEQUAL
} }
else else
bl = defOp->getParent(); bl = (BlockBasic *)iblock->getImmedDom();
} }
else { else {
bl = (BlockBasic *)iblock->getImmedDom(); bl = (BlockBasic *)iblock->getImmedDom();
} }
PcodeOp *newOp = fd->newOp(2,subOp->getAddr()); PcodeOp *newOp = fd->newOp(op->numInput(),op->getAddr());
Varnode *origOutVn = subOp->getOut(); Varnode *origOutVn = op->getOut();
Varnode *outVn = fd->newVarnodeOut(origOutVn->getSize(),origOutVn->getAddr(),newOp); Varnode *outVn = fd->newVarnodeOut(origOutVn->getSize(),origOutVn->getAddr(),newOp);
fd->opSetOpcode(newOp,CPUI_SUBPIECE); fd->opSetOpcode(newOp,op->code());
fd->opSetInput(newOp,invn,0); fd->opSetInput(newOp,invn,0);
fd->opSetInput(newOp,subOp->getIn(1),1); for(int4 i=1;i<op->numInput();++i)
fd->opSetInput(newOp,op->getIn(i),i);
fd->opInsertEnd(newOp, bl); fd->opInsertEnd(newOp, bl);
pullback[inbranch] = outVn; // Cache pullback in case there are other reads pullback[inbranch] = outVn; // Cache pullback in case there are other reads
return outVn; return outVn;
@ -245,10 +252,11 @@ Varnode *ConditionalExecution::resolveIblockRead(PcodeOp *op,int4 inbranch)
else else
return vn; return vn;
} }
if (op->code() == CPUI_MULTIEQUAL) OpCode opc = op->code();
if (opc == CPUI_MULTIEQUAL)
return op->getIn(inbranch); return op->getIn(inbranch);
else if (op->code() == CPUI_SUBPIECE) { else if (opc == CPUI_SUBPIECE || opc == CPUI_INT_ADD || opc == CPUI_PTRSUB) {
return pullbackSubpiece(op, inbranch); return pullbackOp(op, inbranch);
} }
throw LowlevelError("Conditional execution: Illegal op in iblock"); throw LowlevelError("Conditional execution: Illegal op in iblock");
} }

View file

@ -112,7 +112,7 @@ class ConditionalExecution {
bool testMultiRead(Varnode *vn,PcodeOp *op); ///< Can we move the MULTIEQUAL defining p-code of the given Varnode bool testMultiRead(Varnode *vn,PcodeOp *op); ///< Can we move the MULTIEQUAL defining p-code of the given Varnode
bool testRemovability(PcodeOp *op); ///< Test if the given PcodeOp can be removed from \b iblock bool testRemovability(PcodeOp *op); ///< Test if the given PcodeOp can be removed from \b iblock
Varnode *findPullback(int4 inbranch); ///< Find previously constructed pull-back op Varnode *findPullback(int4 inbranch); ///< Find previously constructed pull-back op
Varnode *pullbackSubpiece(PcodeOp *subOp,int4 inbranch); ///< Pull-back SUBPIECE out of the iblock Varnode *pullbackOp(PcodeOp *op,int4 inbranch); ///< Pull-back PcodeOp out of the iblock
Varnode *getNewMulti(PcodeOp *op,BlockBasic *bl); Varnode *getNewMulti(PcodeOp *op,BlockBasic *bl);
Varnode *resolveRead(PcodeOp *op,BlockBasic *bl); ///< Resolve a read op coming through an arbitrary block Varnode *resolveRead(PcodeOp *op,BlockBasic *bl); ///< Resolve a read op coming through an arbitrary block
Varnode *resolveIblockRead(PcodeOp *op,int4 inbranch); ///< Resolve a read op coming through the \b iblock Varnode *resolveIblockRead(PcodeOp *op,int4 inbranch); ///< Resolve a read op coming through the \b iblock

View file

@ -413,8 +413,7 @@ static int4 functionalEqualityLevel0(Varnode *vn1,Varnode *vn2)
return -1; return -1;
} }
if (vn2->isConstant()) return -1; if (vn2->isConstant()) return -1;
if (vn1->isWritten() && vn2->isWritten()) return 1; return 1;
return -1;
} }
/// \brief Try to determine if \b vn1 and \b vn2 contain the same value /// \brief Try to determine if \b vn1 and \b vn2 contain the same value
@ -434,7 +433,11 @@ int4 functionalEqualityLevel(Varnode *vn1,Varnode *vn2,Varnode **res1,Varnode **
{ {
int4 testval = functionalEqualityLevel0(vn1,vn2); int4 testval = functionalEqualityLevel0(vn1,vn2);
if (testval != 1) return testval; if (testval != 1)
return testval;
if (!vn1->isWritten() || !vn2->isWritten()) {
return -1; // Did not find at least one level of match
}
PcodeOp *op1 = vn1->getDef(); PcodeOp *op1 = vn1->getDef();
PcodeOp *op2 = vn2->getDef(); PcodeOp *op2 = vn2->getDef();
OpCode opc = op1->code(); OpCode opc = op1->code();

View file

@ -3,29 +3,43 @@
<!-- <!--
Example where a SUBPIECE gets placed in an iblock that should still be removed. Example where a SUBPIECE gets placed in an iblock that should still be removed.
The predicates should still all collapse to a single "if" body. The predicates should still all collapse to a single "if" body.
Example with INT_ADD in the iblock that should be removed. Should collapse to single if/else.
--> -->
<bytechunk space="ram" offset="0x402d29a8" readonly="true"> <bytechunk space="ram" offset="0x402d29a8" readonly="true">
10402de9eaffffeb 10402de9eaffffeb
24309fe5003093e50120a0e31420c3e5 24309fe5003093e50120a0e31420c3e5
000050e30030a0131730c0151630c015 000050e30030a0131730c0151630c015
1530c0151040bde81eff2fe100003040 1530c0151040bde81eff2fe100003040
0929d9bf026083604360c2607047
</bytechunk> </bytechunk>
<symbol space="ram" offset="0x402d29a8" name="func"/> <symbol space="ram" offset="0x402d29a8" name="func"/>
<symbol space="ram" offset="0x402d295c" name="other"/> <symbol space="ram" offset="0x402d295c" name="other"/>
<symbol space="ram" offset="0x402d29e0" name="iblockadd"/>
</binaryimage> </binaryimage>
<script> <script>
<com>option readonly on</com> <com>option readonly on</com>
<com>set context TMode 1 [ram,0x402d29e0] [ram,0x402d29ef]</com>
<com>parse line struct foo { char buf[0x14]; char w; char x; char y; char z; };</com> <com>parse line struct foo { char buf[0x14]; char w; char x; char y; char z; };</com>
<com>parse line extern void iblockadd(int4 *iptr,int4 a,int4 b,int4 c);</com>
<com>parse line extern foo *other(void);</com> <com>parse line extern foo *other(void);</com>
<com>map addr r0x40300000 foo *glob1</com> <com>map addr r0x40300000 foo *glob1</com>
<com>lo fu func</com> <com>lo fu func</com>
<com>decompile</com> <com>decompile</com>
<com>print C</com> <com>print C</com>
<com>lo fu iblockadd</com>
<com>decompile</com>
<com>print C</com>
</script> </script>
<stringmatch name="Conditional Subpiece #1" min="1" max="1">if</stringmatch> <stringmatch name="Conditional Subpiece #1" min="1" max="1">if \(pfVar</stringmatch>
<stringmatch name="Conditional Subpiece #2" min="0" max="0">\(char\)</stringmatch> <stringmatch name="Conditional Subpiece #2" min="0" max="0">\(char\)</stringmatch>
<stringmatch name="Conditional Subpiece #3" min="1" max="1">glob1-&gt;w = '\\x01';</stringmatch> <stringmatch name="Conditional Subpiece #3" min="1" max="1">glob1-&gt;w = '\\x01';</stringmatch>
<stringmatch name="Conditional Subpiece #4" min="1" max="1">pfVar1-&gt;x = '\\0';</stringmatch> <stringmatch name="Conditional Subpiece #4" min="1" max="1">pfVar1-&gt;x = '\\0';</stringmatch>
<stringmatch name="Conditional Subpiece #5" min="1" max="1">pfVar1-&gt;y = '\\0';</stringmatch> <stringmatch name="Conditional Subpiece #5" min="1" max="1">pfVar1-&gt;y = '\\0';</stringmatch>
<stringmatch name="Conditional Subpiece #6" min="1" max="1">pfVar1-&gt;z = '\\0';</stringmatch> <stringmatch name="Conditional Subpiece #6" min="1" max="1">pfVar1-&gt;z = '\\0';</stringmatch>
<stringmatch name="Conditional Add #1" min="1" max="1">if \(a</stringmatch>
<stringmatch name="Conditional Add #2" min="1" max="1">\*iptr = b;
iptr\[2\] = c;</stringmatch>
<stringmatch name="Conditional Add #3" min="1" max="1">else \{
iptr\[1\] = c;
iptr\[3\] = b;</stringmatch>
</decompilertest> </decompilertest>