diff --git a/Ghidra/Features/Decompiler/certification.manifest b/Ghidra/Features/Decompiler/certification.manifest index e3219bfa2b..e3d0538c50 100644 --- a/Ghidra/Features/Decompiler/certification.manifest +++ b/Ghidra/Features/Decompiler/certification.manifest @@ -17,6 +17,7 @@ src/decompile/datatests/ccmp.xml||GHIDRA||||END| src/decompile/datatests/concat.xml||GHIDRA||||END| src/decompile/datatests/concatsplit.xml||GHIDRA||||END| src/decompile/datatests/condconst.xml||GHIDRA||||END| +src/decompile/datatests/condexesub.xml||GHIDRA||||END| src/decompile/datatests/condmulti.xml||GHIDRA||||END| src/decompile/datatests/convert.xml||GHIDRA||||END| src/decompile/datatests/deadvolatile.xml||GHIDRA||||END| diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/condexe.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/condexe.cc index a4589a5164..0bc8d92c8e 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/condexe.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/condexe.cc @@ -106,14 +106,6 @@ bool ConditionalExecution::verifySameCondition(void) if (tester.getFlip()) init2a_true = !init2a_true; - int4 multislot = tester.getMultiSlot(); - if (multislot != -1) { - // This is a direct split - directsplit = true; - posta_outslot = (multislot == prea_inslot) ? 0 : 1; - if (init2a_true) - posta_outslot = 1 - posta_outslot; - } return true; } @@ -126,15 +118,12 @@ bool ConditionalExecution::testMultiRead(Varnode *vn,PcodeOp *op) { if (op->getParent() == iblock) { - if (!directsplit) { - if (op->code() == CPUI_COPY) // The COPY is tested separately - return true; // If the COPY's output reads can be altered, then -vn- can be altered - return false; - } + if (op->code() == CPUI_COPY || op->code() == CPUI_SUBPIECE) // The copy-like tested separately + return true; // If the COPY's output reads can be altered, then -vn- can be altered + return false; } if (op->code() == CPUI_RETURN) { if ((op->numInput() < 2)||(op->getIn(1) != vn)) return false; // Only test for flow thru to return value - returnop.push_back(op); // mark that CPUI_RETURN needs special handling } return true; } @@ -148,78 +137,65 @@ bool ConditionalExecution::testOpRead(Varnode *vn,PcodeOp *op) { if (op->getParent() == iblock) return true; - if ((op->code() == CPUI_RETURN)&&(!directsplit)) { - if ((op->numInput() < 2)||(op->getIn(1) != vn)) return false; // Only test for flow thru to return value - PcodeOp *copyop = vn->getDef(); - if (copyop->code() == CPUI_COPY) { - // Ordinarily, if -vn- is produced by a COPY we want to return false here because the propagation - // hasn't had time to happen here. But if the flow is into a RETURN this can't propagate, so - // we allow this as a read that can be altered. (We have to move the COPY) - Varnode *invn = copyop->getIn(0); - if (!invn->isWritten()) return false; + PcodeOp *writeOp = vn->getDef(); + if (writeOp->code() == CPUI_COPY || writeOp->code() == CPUI_SUBPIECE) { + Varnode *invn = writeOp->getIn(0); + if (invn->isWritten()) { PcodeOp *upop = invn->getDef(); if ((upop->getParent() == iblock)&&(upop->code() != CPUI_MULTIEQUAL)) return false; - returnop.push_back(op); - return true; } + else if (invn->isFree()) + return false; + return true; } return false; } -/// \brief Prebuild a replacement MULTIEQUAL for output Varnode of the given PcodeOp in \b posta_block -/// -/// The new op will hold the same data-flow as the original Varnode once a new -/// edge into \b posta_block is created. -/// \param op is the given PcodeOp -void ConditionalExecution::predefineDirectMulti(PcodeOp *op) +/// \param inbranch is the iblock incoming branch to pullback through +/// \return the output of the previous pullback op, or null +Varnode *ConditionalExecution::findPullback(int4 inbranch) { - PcodeOp *newop = fd->newOp(posta_block->sizeIn()+1,posta_block->getStart()); - Varnode *outvn = op->getOut(); - Varnode *newoutvn; - newoutvn = fd->newVarnodeOut(outvn->getSize(),outvn->getAddr(),newop); - fd->opSetOpcode(newop,CPUI_MULTIEQUAL); - Varnode *vn; - int4 inslot = iblock->getOutRevIndex(posta_outslot); - for(int4 i=0;isizeIn();++i) { - if (i==inslot) - vn = op->getIn(1-camethruposta_slot); - else - vn = newoutvn; - fd->opSetInput(newop,vn,i); - } - fd->opSetInput(newop,op->getIn(camethruposta_slot),posta_block->sizeIn()); - fd->opInsertBegin(newop,posta_block); - - // Cache this new data flow holder - replacement[posta_block->getIndex()] = newoutvn; + while(pullback.size() <= inbranch) + pullback.push_back((Varnode *)0); + return pullback[inbranch]; } -/// In the \e direct \e split case, MULTIEQUALs in the body block (\b posta_block) -/// must update their flow to account for \b iblock being removed and a new -/// block flowing into the body block. -void ConditionalExecution::adjustDirectMulti(void) +/// 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 +/// \param inbranch is the direction to pullback from +/// \return the output Varnode of the new SUBPIECE +Varnode *ConditionalExecution::pullbackSubpiece(PcodeOp *subOp,int4 inbranch) { - list::const_iterator iter; - PcodeOp *op; - iter = posta_block->beginOp(); - int4 inslot = iblock->getOutRevIndex(posta_outslot); - while(iter != posta_block->endOp()) { - op = *iter++; - if (op->code() != CPUI_MULTIEQUAL) continue; - Varnode *vn = op->getIn(inslot); - if (vn->isWritten()&&(vn->getDef()->getParent() == iblock)) { - if (vn->getDef()->code() != CPUI_MULTIEQUAL) - throw LowlevelError("Cannot push non-trivial operation"); - // Flow that stays in iblock, comes from modified side - fd->opSetInput(op,vn->getDef()->getIn(1-camethruposta_slot),inslot); - // Flow from unmodified side, forms new branch - vn = vn->getDef()->getIn(camethruposta_slot); + Varnode *invn = findPullback(inbranch); // Look for pullback constructed for a previous read + if (invn != (Varnode *)0) + return invn; + invn = subOp->getIn(0); + BlockBasic *bl; + if (invn->isWritten()) { + PcodeOp *defOp = invn->getDef(); + if (defOp->getParent() == iblock) { + bl = (BlockBasic *)iblock->getIn(inbranch); + invn = defOp->getIn(inbranch); // defOp must by MULTIEQUAL } - fd->opInsertInput(op,vn,op->numInput()); + else + bl = defOp->getParent(); } + else { + bl = (BlockBasic *)iblock->getImmedDom(); + } + PcodeOp *newOp = fd->newOp(2,subOp->getAddr()); + Varnode *origOutVn = subOp->getOut(); + Varnode *outVn = fd->newVarnodeOut(origOutVn->getSize(),origOutVn->getAddr(),newOp); + fd->opSetOpcode(newOp,CPUI_SUBPIECE); + fd->opSetInput(newOp,invn,0); + fd->opSetInput(newOp,subOp->getIn(1),1); + fd->opInsertEnd(newOp, bl); + pullback[inbranch] = outVn; // Cache pullback in case there are other reads + return outVn; } /// \brief Create a MULTIEQUAL in the given block that will hold data-flow from the given PcodeOp @@ -249,6 +225,67 @@ Varnode *ConditionalExecution::getNewMulti(PcodeOp *op,BlockBasic *bl) return newoutvn; } +/// Given an op in the \b iblock and the basic block of another op that reads the output Varnode, +/// calculate the replacement Varnode for the read. +/// \param op is the given op in the \b iblock +/// \param bl is the basic block of the read +/// \return the replacement Varnode +Varnode *ConditionalExecution::resolveRead(PcodeOp *op,BlockBasic *bl) + +{ + Varnode *res; + if (bl->sizeIn()==1) { + // Since dominator is iblock, In(0) must be iblock + // Figure what side of -iblock- we came through + int4 slot = (bl->getInRevIndex(0) == posta_outslot) ? camethruposta_slot : 1-camethruposta_slot; + res = resolveIblockRead(op,slot); + } + else + res = getNewMulti(op,bl); + return res; +} + +/// \param op is the \b iblock op whose output is being read +/// \param inbranch is the known direction of the reading op +/// \return the replacement Varnode to use for the read +Varnode *ConditionalExecution::resolveIblockRead(PcodeOp *op,int4 inbranch) + +{ + if (op->code() == CPUI_COPY) { + Varnode *vn = op->getIn(0); + if (vn->isWritten()) { + PcodeOp *defOp = vn->getDef(); + if (defOp->code() == CPUI_MULTIEQUAL && defOp->getParent() == iblock) + op = defOp; + } + else + return vn; + } + if (op->code() == CPUI_MULTIEQUAL) + return op->getIn(inbranch); + else if (op->code() == CPUI_SUBPIECE) { + return pullbackSubpiece(op, inbranch); + } + throw LowlevelError("Conditional execution: Illegal op in iblock"); +} + +/// \brief Get the replacement Varnode for the output of a MULTIEQUAL in the \b iblock, given the op reading it +/// +/// \param op is the MULTIEQUAL from \b iblock +/// \param readop is the PcodeOp reading the output Varnode +/// \param slot is the input slot being read +/// \return the Varnode to use as a replacement +Varnode *ConditionalExecution::getMultiequalRead(PcodeOp *op,PcodeOp *readop,int4 slot) + +{ + BlockBasic *bl = readop->getParent(); + BlockBasic *inbl = (BlockBasic *)bl->getIn(slot); + if (inbl != iblock) + return getReplacementRead(op, inbl); + int4 s = (bl->getInRevIndex(slot) == posta_outslot) ? camethruposta_slot : 1-camethruposta_slot; + return resolveIblockRead(op,s); +} + /// \brief Find a replacement Varnode for the output of the given PcodeOp that is read in the given block /// /// The replacement Varnode must be valid for everything below (dominated) by the block. @@ -278,15 +315,7 @@ Varnode *ConditionalExecution::getReplacementRead(PcodeOp *op,BlockBasic *bl) replacement[bl->getIndex()] = (*iter).second; return (*iter).second; } - Varnode *res; - if (curbl->sizeIn()==1) { - // Since dominator is iblock, In(0) must be iblock - // Figure what side of -iblock- we came through - int4 slot = (curbl->getInRevIndex(0) == posta_outslot) ? camethruposta_slot : 1-camethruposta_slot; - res = op->getIn(slot); - } - else - res = getNewMulti(op,curbl); + Varnode *res = resolveRead(op,curbl); replacement[curbl->getIndex()] = res; if (curbl != bl) replacement[bl->getIndex()] = res; @@ -299,14 +328,8 @@ Varnode *ConditionalExecution::getReplacementRead(PcodeOp *op,BlockBasic *bl) void ConditionalExecution::doReplacement(PcodeOp *op) { - if (op->code() == CPUI_COPY) { - if (op->getOut()->hasNoDescend()) // Verify that this has been dealt with by fixReturnOp - return; - // It could be a COPY internal to iblock, we need to remove it like any other op - } replacement.clear(); - if (directsplit) - predefineDirectMulti(op); + pullback.clear(); Varnode *vn = op->getOut(); list::const_iterator iter = vn->beginDescend(); while(iter != vn->endDescend()) { @@ -315,20 +338,22 @@ void ConditionalExecution::doReplacement(PcodeOp *op) BlockBasic *bl = readop->getParent(); Varnode *rvn; if (bl == iblock) { - if (directsplit) - fd->opSetInput(readop,op->getIn(1-camethruposta_slot),slot); // We know op is MULTIEQUAL - else - fd->opUnsetInput(readop,slot); + fd->opUnsetInput(readop,slot); } else { if (readop->code() == CPUI_MULTIEQUAL) { - BlockBasic *inbl = (BlockBasic *)bl->getIn(slot); - if (inbl == iblock) { - int4 s = (bl->getInRevIndex(slot) == posta_outslot) ? camethruposta_slot : 1-camethruposta_slot; - rvn = op->getIn(s); - } - else - rvn = getReplacementRead(op,inbl); + rvn = getMultiequalRead(op, readop, slot); + } + else if (readop->code() == CPUI_RETURN) { // Cannot replace input of RETURN directly, create COPY to hold input + Varnode *retvn = readop->getIn(1); + PcodeOp *newcopyop = fd->newOp(1,readop->getAddr()); + fd->opSetOpcode(newcopyop,CPUI_COPY); + Varnode *outvn = fd->newVarnodeOut(retvn->getSize(),retvn->getAddr(),newcopyop); // Preserve the CPUI_RETURN storage address + fd->opSetInput(readop,outvn,1); + fd->opInsertBefore(newcopyop,readop); + readop = newcopyop; + slot = 0; + rvn = getReplacementRead(op,bl); } else rvn = getReplacementRead(op,bl); @@ -339,28 +364,6 @@ void ConditionalExecution::doReplacement(PcodeOp *op) } } -/// \brief Reproduce COPY data-flow into RETURN ops affected by the removal of \b iblock -void ConditionalExecution::fixReturnOp(void) - -{ - for(int4 i=0;igetIn(1); - PcodeOp *iblockop = retvn->getDef(); - Varnode *invn; - if (iblockop->code() == CPUI_COPY) - invn = iblockop->getIn(0); // This must either be from MULTIEQUAL or something written outside of iblock - else - invn = retvn; - PcodeOp *newcopyop = fd->newOp(1,retop->getAddr()); - fd->opSetOpcode(newcopyop,CPUI_COPY); - Varnode *outvn = fd->newVarnodeOut(retvn->getSize(),retvn->getAddr(),newcopyop); // Preserve the CPUI_RETURN storage address - fd->opSetInput(newcopyop,invn,0); - fd->opSetInput(retop,outvn,1); - fd->opInsertBefore(newcopyop,retop); - } -} - /// \param op is the PcodeOp within \b iblock to test /// \return \b true if it is removable bool ConditionalExecution::testRemovability(PcodeOp *op) @@ -385,6 +388,7 @@ bool ConditionalExecution::testRemovability(PcodeOp *op) if (op->code()==CPUI_INDIRECT) return false; vn = op->getOut(); + if (vn->isAddrTied()) return false; if (vn != (Varnode *)0) { bool hasnodescend = true; for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) { @@ -408,7 +412,6 @@ bool ConditionalExecution::verify(void) { prea_inslot = 0; posta_outslot = 0; - directsplit = false; if (!testIBlock()) return false; if (!findInitPre()) return false; @@ -420,7 +423,6 @@ bool ConditionalExecution::verify(void) posta_block = (BlockBasic *)iblock->getOut(posta_outslot); postb_block = (BlockBasic *)iblock->getOut(1-posta_outslot); - returnop.clear(); list::const_iterator iter; iter = iblock->endOp(); if (iter != iblock->beginOp()) @@ -456,50 +458,7 @@ bool ConditionalExecution::trial(BlockBasic *ib) { iblock = ib; if (!verify()) return false; - - PcodeOp *cbranch_copy; - BlockBasic *initblock_copy; - BlockBasic *iblock_copy; - int4 prea_inslot_copy; - bool init2a_true_copy; - bool iblock2posta_true_copy; - int4 camethruposta_slot_copy; - int4 posta_outslot_copy; - BlockBasic *posta_block_copy; - BlockBasic *postb_block_copy; - bool directsplit_copy; - - for(;;) { - if (!directsplit) return true; - // Save off the data for current iblock - cbranch_copy = cbranch; - initblock_copy = initblock; - iblock_copy = iblock; - prea_inslot_copy = prea_inslot; - init2a_true_copy = init2a_true; - iblock2posta_true_copy = iblock2posta_true; - camethruposta_slot_copy = camethruposta_slot; - posta_outslot_copy = posta_outslot; - posta_block_copy = posta_block; - postb_block_copy = postb_block; - directsplit_copy = directsplit; - - iblock = posta_block; - if (!verify()) { - cbranch = cbranch_copy; - initblock = initblock_copy; - iblock = iblock_copy; - prea_inslot = prea_inslot_copy; - init2a_true = init2a_true_copy; - iblock2posta_true = iblock2posta_true_copy; - camethruposta_slot = camethruposta_slot_copy; - posta_outslot = posta_outslot_copy; - posta_block = posta_block_copy; - postb_block = postb_block_copy; - directsplit = directsplit_copy; - return true; - } - } + return true; } /// We assume the last call to verify() returned \b true @@ -508,31 +467,20 @@ void ConditionalExecution::execute(void) { list::iterator iter; PcodeOp *op; + bool notdone; - fixReturnOp(); // Patch any data-flow thru to CPUI_RETURN - if (!directsplit) { - iter = iblock->beginOp(); - while(iter != iblock->endOp()) { - op = *iter++; - if (!op->isBranch()) - doReplacement(op); // Remove all read refs of op - fd->opDestroy(op); // Then destroy op - } - fd->removeFromFlowSplit(iblock,(posta_outslot != camethruposta_slot)); - } - else { - adjustDirectMulti(); - iter = iblock->beginOp(); - while(iter != iblock->endOp()) { - op = *iter++; - if (op->code() == CPUI_MULTIEQUAL) { // Only adjust MULTIEQUALs - doReplacement(op); - fd->opDestroy(op); - } - // Branch stays, other operations stay - } - fd->switchEdge(iblock->getIn(camethruposta_slot),iblock,posta_block); - } + iter = iblock->endOp(); // Remove ops in reverse order + --iter; + do { + op = *iter; + notdone = iter != iblock->beginOp(); + if (notdone) + --iter; + if (!op->isBranch()) + doReplacement(op); // Remove all read refs of op + fd->opDestroy(op); // Then destroy op + } while(notdone); + fd->removeFromFlowSplit(iblock,(posta_outslot != camethruposta_slot)); } int4 ActionConditionalExe::apply(Funcdata &data) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/condexe.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/condexe.hh index 2ac07526af..033fb90af6 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/condexe.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/condexe.hh @@ -113,9 +113,8 @@ class ConditionalExecution { int4 posta_outslot; ///< The \b out edge from iblock to posta BlockBasic *posta_block; ///< First block in posta path BlockBasic *postb_block; ///< First block in postb path - bool directsplit; ///< True if this the \e direct \e split variation map replacement; ///< Map from block to replacement Varnode for (current) Varnode - vector returnop; ///< RETURN ops that have flow coming out of the iblock + vector pullback; ///< Outputs of ops that have been pulled back from \b iblock for (current) Varnode vector heritageyes; ///< Boolean array indexed by address space indicating whether the space is heritaged void buildHeritageArray(void); @@ -123,14 +122,16 @@ class ConditionalExecution { bool findInitPre(void); ///< Find \b initblock, based on \b iblock bool verifySameCondition(void); ///< Verify that \b initblock and \b iblock branch on the same condition bool testOpRead(Varnode *vn,PcodeOp *op); ///< Can we move the (non MULTIEQUAL) defining p-code of the given Varnode - bool testMultiRead(Varnode *vn,PcodeOp *op); ///< Can we mave 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 - void predefineDirectMulti(PcodeOp *op); - void adjustDirectMulti(void); ///< Update inputs to any MULTIEQUAL in the direct block + Varnode *findPullback(int4 inbranch); ///< Find previously constructed pull-back op + Varnode *pullbackSubpiece(PcodeOp *subOp,int4 inbranch); ///< Pull-back SUBPIECE 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 + Varnode *getMultiequalRead(PcodeOp *op,PcodeOp *readop,int4 slot); Varnode *getReplacementRead(PcodeOp *op,BlockBasic *bl); void doReplacement(PcodeOp *op); ///< Replace the data-flow for the given PcodeOp in \b iblock - void fixReturnOp(void); bool verify(void); ///< Verify that we have a removable \b iblock public: ConditionalExecution(Funcdata *f); ///< Constructor diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc index cbfc852283..7abc6ac385 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc @@ -4292,11 +4292,13 @@ void ActionConditionalConst::handlePhiNodes(Varnode *varVn,Varnode *constVn,vect /// For each read op, check that is in or dominated by a specific block we known /// the Varnode is constant in. /// \param varVn is the given Varnode -/// \param constVn is the constant Varnode to replace with +/// \param constVn is the constant Varnode to replace with (may be null) +/// \param constVal is the constant value being propagated /// \param constBlock is the block which dominates ops reading the constant value /// \param useMultiequal is \b true if conditional constants can be applied to MULTIEQUAL ops /// \param data is the function being analyzed -void ActionConditionalConst::propagateConstant(Varnode *varVn,Varnode *constVn,FlowBlock *constBlock,bool useMultiequal,Funcdata &data) +void ActionConditionalConst::propagateConstant(Varnode *varVn,Varnode *constVn,uintb constVal, + FlowBlock *constBlock,bool useMultiequal,Funcdata &data) { vector phiNodeEdges; @@ -4333,6 +4335,8 @@ void ActionConditionalConst::propagateConstant(Varnode *varVn,Varnode *constVn,F // ...unless COPY is into something more interesting } if (constBlock->dominates(op->getParent())) { + if (constVn == (Varnode *)0) + constVn = data.newConstant(varVn->getSize(), constVal); if (opc == CPUI_RETURN){ // CPUI_RETURN ops can't directly take constants // as inputs @@ -4350,8 +4354,11 @@ void ActionConditionalConst::propagateConstant(Varnode *varVn,Varnode *constVn,F count += 1; // We made a change } } - if (!phiNodeEdges.empty()) + if (!phiNodeEdges.empty()) { + if (constVn == (Varnode *)0) + constVn = data.newConstant(varVn->getSize(), constVal); handlePhiNodes(varVn, constVn, phiNodeEdges, data); + } } int4 ActionConditionalConst::apply(Funcdata &data) @@ -4367,15 +4374,26 @@ int4 ActionConditionalConst::apply(Funcdata &data) useMultiequal = false; // Don't propagate into MULTIEQUAL } const BlockGraph &blockGraph(data.getBasicBlocks()); + bool blockdom[2]; for(int4 i=0;ilastOp(); if (cBranch == (PcodeOp *)0 || cBranch->code() != CPUI_CBRANCH) continue; Varnode *boolVn = cBranch->getIn(1); + blockdom[0] = bl->getOut(0)->restrictedByConditional(bl); // Make sure boolean constant holds down false branch + blockdom[1] = bl->getOut(1)->restrictedByConditional(bl); + if (!blockdom[0] && !blockdom[1]) continue; + bool flipEdge = cBranch->isBooleanFlip(); + if (boolVn->loneDescend() == (PcodeOp *)0) { // If the boolean is read more than once + // Search for implied constants, bool=0 down false branch, bool=1 down true branch + if (blockdom[0]) + propagateConstant(boolVn, (Varnode *)0, flipEdge ? 1 : 0, bl->getFalseOut(), useMultiequal, data); + if (blockdom[1]) + propagateConstant(boolVn, (Varnode *)0, flipEdge ? 0 : 1, bl->getTrueOut(), useMultiequal, data); + } if (!boolVn->isWritten()) continue; PcodeOp *compOp = boolVn->getDef(); OpCode opc = compOp->code(); - bool flipEdge = cBranch->isBooleanFlip(); if (opc == CPUI_BOOL_NEGATE) { flipEdge = !flipEdge; boolVn = compOp->getIn(0); @@ -4400,11 +4418,11 @@ int4 ActionConditionalConst::apply(Funcdata &data) constVn = varVn; varVn = tmp; } + if (varVn->loneDescend() != (PcodeOp *)0) continue; if (flipEdge) constEdge = 1 - constEdge; - FlowBlock *constBlock = bl->getOut(constEdge); - if (!constBlock->restrictedByConditional(bl)) continue; // Make sure condition holds - propagateConstant(varVn,constVn,constBlock,useMultiequal,data); + if (!blockdom[constEdge]) continue; // Make sure condition holds + propagateConstant(varVn,constVn,0,bl->getOut(constEdge),useMultiequal,data); } return 0; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh index 3c6ac0fa4c..71aab9f96c 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.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. @@ -574,7 +574,7 @@ class ActionConditionalConst : public Action { static Varnode *placeCopy(PcodeOp *op,BlockBasic *bl,Varnode *constVn,Funcdata &data); static void placeMultipleConstants(vector &phiNodeEdges,vector &marks,Varnode *constVn,Funcdata &data); void handlePhiNodes(Varnode *varVn,Varnode *constVn,vector &phiNodeEdges,Funcdata &data); - void propagateConstant(Varnode *varVn,Varnode *constVn,FlowBlock *constBlock,bool useMultiequal,Funcdata &data); + void propagateConstant(Varnode *varVn,Varnode *constVn,uintb constVal,FlowBlock *constBlock,bool useMultiequal,Funcdata &data); public: ActionConditionalConst(const string &g) : Action(0,"condconst",g) {} ///< Constructor virtual Action *clone(const ActionGroupList &grouplist) const { diff --git a/Ghidra/Features/Decompiler/src/decompile/datatests/condexesub.xml b/Ghidra/Features/Decompiler/src/decompile/datatests/condexesub.xml new file mode 100644 index 0000000000..2462c6f54d --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/datatests/condexesub.xml @@ -0,0 +1,31 @@ + + + + + 10402de9eaffffeb +24309fe5003093e50120a0e31420c3e5 +000050e30030a0131730c0151630c015 +1530c0151040bde81eff2fe100003040 + + + + + +if +\(char\) +glob1->w = '\\x01'; +pfVar1->x = '\\0'; +pfVar1->y = '\\0'; +pfVar1->z = '\\0'; +