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

View file

@ -413,8 +413,7 @@ static int4 functionalEqualityLevel0(Varnode *vn1,Varnode *vn2)
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
@ -434,7 +433,11 @@ int4 functionalEqualityLevel(Varnode *vn1,Varnode *vn2,Varnode **res1,Varnode **
{
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 *op2 = vn2->getDef();
OpCode opc = op1->code();

View file

@ -3,29 +3,43 @@
<!--
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.
Example with INT_ADD in the iblock that should be removed. Should collapse to single if/else.
-->
<bytechunk space="ram" offset="0x402d29a8" readonly="true">
10402de9eaffffeb
24309fe5003093e50120a0e31420c3e5
000050e30030a0131730c0151630c015
1530c0151040bde81eff2fe100003040
0929d9bf026083604360c2607047
</bytechunk>
<symbol space="ram" offset="0x402d29a8" name="func"/>
<symbol space="ram" offset="0x402d295c" name="other"/>
<symbol space="ram" offset="0x402d29e0" name="iblockadd"/>
</binaryimage>
<script>
<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 extern void iblockadd(int4 *iptr,int4 a,int4 b,int4 c);</com>
<com>parse line extern foo *other(void);</com>
<com>map addr r0x40300000 foo *glob1</com>
<com>lo fu func</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu iblockadd</com>
<com>decompile</com>
<com>print C</com>
</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 #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 #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 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>