diff --git a/Ghidra/Features/Decompiler/certification.manifest b/Ghidra/Features/Decompiler/certification.manifest index 8d3f7a6ae8..710f82ea78 100644 --- a/Ghidra/Features/Decompiler/certification.manifest +++ b/Ghidra/Features/Decompiler/certification.manifest @@ -50,6 +50,7 @@ src/decompile/datatests/noforloop_alias.xml||GHIDRA||||END| src/decompile/datatests/noforloop_globcall.xml||GHIDRA||||END| src/decompile/datatests/noforloop_iterused.xml||GHIDRA||||END| src/decompile/datatests/offsetarray.xml||GHIDRA||||END| +src/decompile/datatests/orcompare.xml||GHIDRA||||END| src/decompile/datatests/packstructaccess.xml||GHIDRA||||END| src/decompile/datatests/partialmerge.xml||GHIDRA||||END| src/decompile/datatests/partialsplit.xml||GHIDRA||||END| diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc index 02faf8d6d1..76963accce 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc @@ -5518,7 +5518,6 @@ void ActionDatabase::universalAction(Architecture *conf) actprop->addRule( new RulePiece2Zext("analysis") ); actprop->addRule( new RulePiece2Sext("analysis") ); actprop->addRule( new RulePopcountBoolXor("analysis") ); - actprop->addRule( new RuleOrMultiBool("analysis") ); actprop->addRule( new RuleXorSwap("analysis") ); actprop->addRule( new RuleLzcountShiftBool("analysis") ); actprop->addRule( new RuleFloatSign("analysis") ); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/double.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/double.cc index 840ed38365..ab4257ed5b 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/double.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/double.cc @@ -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. @@ -1124,9 +1124,6 @@ int4 SplitVarnode::applyRuleIn(SplitVarnode &in,Funcdata &data) break; case CPUI_INT_OR: { - Equal2Form equal2form; - if (equal2form.applyRule(in,workop,workishi,data)) - return 1; LogicalForm logicalform; if (logicalform.applyRule(in,workop,workishi,data)) return 1; @@ -1134,9 +1131,6 @@ int4 SplitVarnode::applyRuleIn(SplitVarnode &in,Funcdata &data) break; case CPUI_INT_XOR: { - Equal2Form equal2form; - if (equal2form.applyRule(in,workop,workishi,data)) - return 1; LogicalForm logicalform; if (logicalform.applyRule(in,workop,workishi,data)) return 1; @@ -1151,6 +1145,9 @@ int4 SplitVarnode::applyRuleIn(SplitVarnode &in,Funcdata &data) Equal1Form equal1form; if (equal1form.applyRule(in,workop,workishi,data)) return 1; + Equal2Form equal2form; + if (equal2form.applyRule(in,workop,workishi,data)) + return 1; } break; case CPUI_INT_LESS: @@ -1870,95 +1867,30 @@ bool Equal1Form::applyRule(SplitVarnode &i,PcodeOp *hop,bool workishi,Funcdata & return false; } -bool Equal2Form::checkLoForm(void) - -{ // Assuming we have equal <- or <- xor <- hi1, verify if we have the full equal form - Varnode *orvnin = orop->getIn(1-orhislot); - if (orvnin == lo1) { // lo2 is an implied 0 - loxor = (PcodeOp *)0; - lo2 = (Varnode *)0; - return true; - } - if (!orvnin->isWritten()) return false; - loxor = orvnin->getDef(); - if (loxor->code() != CPUI_INT_XOR) return false; - if (loxor->getIn(0) == lo1) { - lo2 = loxor->getIn(1); - return true; - } - else if (loxor->getIn(1) == lo1) { - lo2 = loxor->getIn(0); - return true; - } - return false; -} - -bool Equal2Form::fillOutFromOr(Funcdata &data) - -{ // We have filled in either or <- xor <- hi1, OR, or <- hi1 - // Now try to fill in the rest of the form - Varnode *outvn = orop->getOut(); - list::const_iterator iter,enditer; - iter = outvn->beginDescend(); - enditer = outvn->endDescend(); - while(iter != enditer) { - equalop = *iter; - ++iter; - if ((equalop->code() != CPUI_INT_EQUAL)&&(equalop->code() != CPUI_INT_NOTEQUAL)) continue; - if (!equalop->getIn(1)->isConstant()) continue; - if (equalop->getIn(1)->getOffset() != 0) continue; - - if (!checkLoForm()) continue; - if (!replace(data)) continue; - return true; - } - return false; -} - bool Equal2Form::replace(Funcdata &data) { - if ((hi2==(Varnode *)0)&&(lo2==(Varnode *)0)) { - param2.initPartial(in.getSize(),0); // Double precis zero constant - return SplitVarnode::prepareBoolOp(in,param2,equalop); - } - if ((hi2==(Varnode *)0)&&(lo2->isConstant())) { - param2.initPartial(in.getSize(),lo2->getOffset()); - return SplitVarnode::prepareBoolOp(in,param2,equalop); - } - if ((lo2==(Varnode *)0)&&(hi2->isConstant())) { - param2.initPartial(in.getSize(),hi2->getOffset() << 8*lo1->getSize()); - return SplitVarnode::prepareBoolOp(in,param2,equalop); - } - if (lo2 == (Varnode *)0) { - // Equal to a zero extended and shifted var - return false; - } - if (hi2 == (Varnode *)0) { - // Equal to a zero extended var - return false; - } if (hi2->isConstant()&&lo2->isConstant()) { uintb val = hi2->getOffset(); val <<= 8*lo1->getSize(); val |= lo2->getOffset(); param2.initPartial(in.getSize(),val); - return SplitVarnode::prepareBoolOp(in,param2,equalop); + return SplitVarnode::prepareBoolOp(in,param2,boolAndOr); } if (hi2->isConstant()||lo2->isConstant()) { // Some kind of mixed form return false; } param2.initPartial(in.getSize(),lo2,hi2); - return SplitVarnode::prepareBoolOp(in,param2,equalop); + return SplitVarnode::prepareBoolOp(in,param2,boolAndOr); } // Given a known double precis input, look for double precision compares of the form // a == b, a != b // // We look for -// res = ((hi1 ^ hi2) | (lo1 ^ lo2) == 0) -// where hi2 or lo2 may be zero, and optimized out +// res = (hi1 == hi2) && (lo1 == lo2) or +// res = (hi1 != hi2) || (lo1 != lo2) bool Equal2Form::applyRule(SplitVarnode &i,PcodeOp *op,bool workishi,Funcdata &data) { @@ -1967,41 +1899,37 @@ bool Equal2Form::applyRule(SplitVarnode &i,PcodeOp *op,bool workishi,Funcdata &d in = i; hi1 = in.getHi(); lo1 = in.getLo(); - - if (op->code() == CPUI_INT_OR) { - orop = op; - orhislot = op->getSlot(hi1); - hixor = (PcodeOp *)0; - hi2 = (Varnode *)0; - if (fillOutFromOr(data)) { - if (!param2.exceedsConstPrecision()) { - SplitVarnode::replaceBoolOp(data,equalop,in,param2,equalop->code()); - return true; - } + OpCode eqCode = op->code(); + int4 hi1slot = op->getSlot(hi1); + hi2 = op->getIn(1-hi1slot); + Varnode *outvn = op->getOut(); + list::const_iterator iter,enditer; + iter = outvn->beginDescend(); + enditer = outvn->endDescend(); + while(iter != enditer) { + boolAndOr = *iter; + ++iter; + if (eqCode == CPUI_INT_EQUAL && boolAndOr->code() != CPUI_BOOL_AND) continue; + if (eqCode == CPUI_INT_NOTEQUAL && boolAndOr->code() != CPUI_BOOL_OR) continue; + int4 slot = boolAndOr->getSlot(outvn); + Varnode *othervn = boolAndOr->getIn(1-slot); + if (!othervn->isWritten()) continue; + PcodeOp *equalLo = othervn->getDef(); + if (equalLo->code() != eqCode) continue; + if (equalLo->getIn(0) == lo1) { + lo2 = equalLo->getIn(1); } - } - else { // We see an XOR - hixor = op; - xorhislot = hixor->getSlot(hi1); - hi2 = hixor->getIn(1-xorhislot); - Varnode *vn = op->getOut(); - list::const_iterator iter,enditer; - iter = vn->beginDescend(); - enditer = vn->endDescend(); - while(iter != enditer) { - orop = *iter; - ++iter; - if (orop->code() != CPUI_INT_OR) continue; - orhislot = orop->getSlot(vn); - if (fillOutFromOr(data)) { - if (!param2.exceedsConstPrecision()) { - SplitVarnode::replaceBoolOp(data,equalop,in,param2,equalop->code()); - return true; - } - } + else if (equalLo->getIn(1) == lo1) { + lo2 = equalLo->getIn(0); } + else { + continue; + } + if (!replace(data)) continue; + if (param2.exceedsConstPrecision()) continue; + SplitVarnode::replaceBoolOp(data,boolAndOr,in,param2,eqCode); + return true; } - return false; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/double.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/double.hh index 175f6024ae..0b2e9e7b09 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/double.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/double.hh @@ -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. @@ -160,12 +160,8 @@ public: class Equal2Form { SplitVarnode in; Varnode *hi1,*hi2,*lo1,*lo2; - PcodeOp *equalop,*orop; - PcodeOp *hixor,*loxor; - int4 orhislot,xorhislot; + PcodeOp *boolAndOr; SplitVarnode param2; - bool checkLoForm(void); - bool fillOutFromOr(Funcdata &data); bool replace(Funcdata &data); public: bool applyRule(SplitVarnode &i,PcodeOp *op,bool workishi,Funcdata &data); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc index 74a62950c8..d76a799960 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc @@ -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. @@ -672,20 +672,33 @@ uintb PcodeOp::getNZMaskLocal(bool cliploop) const case CPUI_INT_MULT: val = getIn(0)->getNZMask(); resmask = getIn(1)->getNZMask(); - sz1 = (size > sizeof(uintb)) ? 8*size-1 : mostsigbit_set(val); - if (sz1 == -1) - resmask = 0; + if (size > sizeof(uintb)) { + resmask = fullmask; + } else { - sz2 = (size > sizeof(uintb)) ? 8*size-1 : mostsigbit_set(resmask); - if (sz2 == -1) + sz1 = mostsigbit_set(val); + sz2 = mostsigbit_set(resmask); + if (sz1 == -1 || sz2 == -1) { resmask = 0; + } else { - if (sz1 + sz2 < 8*size-2) - fullmask >>= (8*size-2-sz1-sz2); - sz1 = leastsigbit_set(val); - sz2 = leastsigbit_set(resmask); - resmask = (~((uintb)0))<<(sz1+sz2); - resmask &= fullmask; + int4 l1 = leastsigbit_set(val); + int4 l2 = leastsigbit_set(resmask); + sa = l1 + l2; + if (sa >= 8*size) { + resmask = 0; + } + else { + sz1 = sz1 - l1 + 1; + sz2 = sz2 - l2 + 1; + int4 total = sz1 + sz2; + if (sz1 == 1 || sz2 == 1) + total -= 1; + resmask = fullmask; + if (total < 8 * size) + resmask >>= (8*size - total); + resmask = (resmask << sa) & fullmask; + } } } break; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc index 35cad45220..aedfd8fa9c 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc @@ -10101,66 +10101,6 @@ Varnode *RulePopcountBoolXor::getBooleanResult(Varnode *vn,int4 bitPos,int4 &con } } -/// \class RuleOrMultiBool -/// \brief Simplify boolean expressions that are combined through INT_OR -/// -/// Convert expressions involving boolean values b1 and b2: -/// - `(b1 << 6) | (b2 << 2) != 0 => b1 || b2 -void RuleOrMultiBool::getOpList(vector &oplist) const - -{ - oplist.push_back(CPUI_INT_OR); -} - -int4 RuleOrMultiBool::applyOp(PcodeOp *op,Funcdata &data) - -{ - Varnode *outVn = op->getOut(); - list::const_iterator iter; - - if (popcount(outVn->getNZMask()) != 2) return 0; - for(iter=outVn->beginDescend();iter!=outVn->endDescend();++iter) { - PcodeOp *baseOp = *iter; - OpCode opc = baseOp->code(); - // Result of INT_OR must be compared with zero - if (opc != CPUI_INT_EQUAL && opc != CPUI_INT_NOTEQUAL) continue; - Varnode *zerovn = baseOp->getIn(1); - if (!zerovn->isConstant()) continue; - if (zerovn->getOffset() != 0) continue; - int4 pos0 = leastsigbit_set(outVn->getNZMask()); - int4 pos1 = mostsigbit_set(outVn->getNZMask()); - int4 constRes0,constRes1; - Varnode *b1 = RulePopcountBoolXor::getBooleanResult(outVn, pos0, constRes0); - if (b1 == (Varnode *)0 && constRes0 != 1) continue; - Varnode *b2 = RulePopcountBoolXor::getBooleanResult(outVn, pos1, constRes1); - if (b2 == (Varnode *)0 && constRes1 != 1) continue; - if (b1 == (Varnode *)0 && b2 == (Varnode *)0) continue; - - if (b1 == (Varnode *)0) - b1 = data.newConstant(1, 1); - if (b2 == (Varnode *)0) - b2 = data.newConstant(1, 1); - if (opc == CPUI_INT_EQUAL) { - PcodeOp *newOp = data.newOp(2,baseOp->getAddr()); - Varnode *notIn = data.newUniqueOut(1, newOp); - data.opSetOpcode(newOp, CPUI_BOOL_OR); - data.opSetInput(newOp, b1, 0); - data.opSetInput(newOp, b2, 1); - data.opInsertBefore(newOp, baseOp); - data.opRemoveInput(baseOp, 1); - data.opSetInput(baseOp, notIn, 0); - data.opSetOpcode(baseOp, CPUI_BOOL_NEGATE); - } - else { - data.opSetOpcode(baseOp, CPUI_BOOL_OR); - data.opSetInput(baseOp, b1, 0); - data.opSetInput(baseOp, b2, 1); - } - return 1; - } - return 0; -} - /// \brief Return \b true if concatenating with a SUBPIECE of the given Varnode is unusual /// /// \param vn is the given Varnode @@ -10550,53 +10490,65 @@ int4 RuleFloatSignCleanup::applyOp(PcodeOp *op,Funcdata &data) void RuleOrCompare::getOpList(vector &oplist) const { - oplist.push_back(CPUI_INT_EQUAL); - oplist.push_back(CPUI_INT_NOTEQUAL); + oplist.push_back(CPUI_INT_OR); } int4 RuleOrCompare::applyOp(PcodeOp *op,Funcdata &data) { - // make sure the comparison is against 0 - if (! op->getIn(1)->constantMatch(0)) return 0; + Varnode *outvn = op->getOut(); + list::const_iterator iter; + bool hasCompares = false; + for(iter=outvn->beginDescend();iter!=outvn->endDescend();++iter) { + PcodeOp *compOp = *iter; + OpCode opc = compOp->code(); + if (opc != CPUI_INT_EQUAL && opc != CPUI_INT_NOTEQUAL) + return 0; + if (!compOp->getIn(1)->constantMatch(0)) + return 0; + hasCompares = true; + } + if (!hasCompares) + return 0; - // make sure the other operand is an INT_OR - PcodeOp *or_op = op->getIn(0)->getDef(); - if (or_op == (PcodeOp *)0) return 0; - if (or_op->code() != CPUI_INT_OR) return 0; - - Varnode* V = or_op->getIn(0); - Varnode* W = or_op->getIn(1); + Varnode* V = op->getIn(0); + Varnode* W = op->getIn(1); // make sure V and W are in SSA form if (V->isFree()) return 0; if (W->isFree()) return 0; - // construct the new segment: - // if the original condition was INT_EQUAL: BOOL_AND(INT_EQUAL(V, 0:|V|), INT_EQUAL(W, 0:|W|)) - // if the original condition was INT_NOTEQUAL: BOOL_OR(INT_NOTEQUAL(V, 0:|V|), INT_NOTEQUAL(W, 0:|W|)) - Varnode* zero_V = data.newConstant(V->getSize(), 0); - Varnode* zero_W = data.newConstant(W->getSize(), 0); - PcodeOp* eq_V = data.newOp(2, op->getAddr()); - data.opSetOpcode(eq_V, op->code()); - data.opSetInput(eq_V, V, 0); - data.opSetInput(eq_V, zero_V, 1); - PcodeOp* eq_W = data.newOp(2, op->getAddr()); - data.opSetOpcode(eq_W, op->code()); - data.opSetInput(eq_W, W, 0); - data.opSetInput(eq_W, zero_W, 1); + iter = outvn->beginDescend(); + while(iter!=outvn->endDescend()) { + PcodeOp *equalOp = *iter; + OpCode opc = equalOp->code(); + ++iter; // Advance iterator immediately as equalOp gets modified + // construct the new segment: + // if the original condition was INT_EQUAL: BOOL_AND(INT_EQUAL(V, 0:|V|), INT_EQUAL(W, 0:|W|)) + // if the original condition was INT_NOTEQUAL: BOOL_OR(INT_NOTEQUAL(V, 0:|V|), INT_NOTEQUAL(W, 0:|W|)) + Varnode* zero_V = data.newConstant(V->getSize(), 0); + Varnode* zero_W = data.newConstant(W->getSize(), 0); + PcodeOp* eq_V = data.newOp(2, equalOp->getAddr()); + data.opSetOpcode(eq_V, opc); + data.opSetInput(eq_V, V, 0); + data.opSetInput(eq_V, zero_V, 1); + PcodeOp* eq_W = data.newOp(2, equalOp->getAddr()); + data.opSetOpcode(eq_W, opc); + data.opSetInput(eq_W, W, 0); + data.opSetInput(eq_W, zero_W, 1); - Varnode* eq_V_out = data.newUniqueOut(1, eq_V); - Varnode* eq_W_out = data.newUniqueOut(1, eq_W); + Varnode* eq_V_out = data.newUniqueOut(1, eq_V); + Varnode* eq_W_out = data.newUniqueOut(1, eq_W); - // make sure the comparisons' output is already defined - data.opInsertBefore(eq_V, op); - data.opInsertBefore(eq_W, op); + // make sure the comparisons' output is already defined + data.opInsertBefore(eq_V, equalOp); + data.opInsertBefore(eq_W, equalOp); - // change the original INT_EQUAL into a BOOL_AND, and INT_NOTEQUAL becomes BOOL_OR - data.opSetOpcode(op, op->code() == CPUI_INT_EQUAL ? CPUI_BOOL_AND : CPUI_BOOL_OR); - data.opSetInput(op, eq_V_out, 0); - data.opSetInput(op, eq_W_out, 1); + // change the original INT_EQUAL into a BOOL_AND, and INT_NOTEQUAL becomes BOOL_OR + data.opSetOpcode(equalOp, opc == CPUI_INT_EQUAL ? CPUI_BOOL_AND : CPUI_BOOL_OR); + data.opSetInput(equalOp, eq_V_out, 0); + data.opSetInput(equalOp, eq_W_out, 1); + } return 1; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.hh index 20fd92145c..fc27699028 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.hh @@ -1598,17 +1598,6 @@ public: static Varnode *getBooleanResult(Varnode *vn,int4 bitPos,int4 &constRes); }; -class RuleOrMultiBool : public Rule { -public: - RuleOrMultiBool(const string &g) : Rule( g, 0, "ormultibool") {} ///< Constructor - virtual Rule *clone(const ActionGroupList &grouplist) const { - if (!grouplist.contains(getGroup())) return (Rule *)0; - return new RuleOrMultiBool(getGroup()); - } - virtual void getOpList(vector &oplist) const; - virtual int4 applyOp(PcodeOp *op,Funcdata &data); -}; - class RulePiecePathology : public Rule { static bool isPathology(Varnode *vn,Funcdata &data); static int4 tracePathologyForward(PcodeOp *op,Funcdata &data); diff --git a/Ghidra/Features/Decompiler/src/decompile/datatests/orcompare.xml b/Ghidra/Features/Decompiler/src/decompile/datatests/orcompare.xml new file mode 100644 index 0000000000..8d28d7cd16 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/datatests/orcompare.xml @@ -0,0 +1,29 @@ + + + +f30f1efa83ff0a0f94c20fb6d201d283 +fe140f94c00fb6c0c1e007b901000000 +09c2740f833dd50f0000000f94c10fb6 +c901c989c8c3f30f1efa81fec8000000 +0f94c00fb6c0c1e00283ff640f94c10f +b6c909c881fa2c0100000f94c20fb6d2 +c1e20409d07510833d920f000007ba02 +0000000f44c2c3b801000000c3 + + + + + +if \(a == 10 \|\| b == 0x14\) +if \(\(y != 200 && x != 100\) && z != 300\) +