diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc index a4b2029d3c..bf7103d916 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc @@ -638,6 +638,17 @@ JumpTable *FlowBlock::getJumptable(void) const return jt; } +/// Print a single unique identifier for \b this block +/// \param s is the output stream +void FlowBlock::printShortHeader(ostream &s) const + +{ + s << "Block_" << dec << index; + if (!getStart().isInvalid()) { + s << ':' << getStart(); + } +} + /// Given a string describing a FlowBlock type, return the block_type. /// This is currently only used by the decode() process. /// TODO: Fill in the remaining names and types @@ -1293,8 +1304,24 @@ void BlockGraph::printRaw(ostream &s) const printHeader(s); s << endl; - for(iter=list.begin();iter!=list.end();++iter) - (*iter)->printRaw(s); + if (list.empty()) return; + iter = list.begin(); + FlowBlock *lastBl = *iter; + ++iter; + lastBl->printRaw(s); + for(;iter!=list.end();++iter) { + FlowBlock *curBl = *iter; + lastBl->printRawImpliedGoto(s, curBl); + curBl->printRaw(s); + lastBl = curBl; + } +} + +void BlockGraph::printRawImpliedGoto(ostream &s,const FlowBlock *nextBlock) const + +{ + if (list.empty()) return; + list.back()->printRawImpliedGoto(s, nextBlock); } PcodeOp *BlockGraph::firstOp(void) const @@ -2658,6 +2685,24 @@ void BlockBasic::printRaw(ostream &s) const } } +void BlockBasic::printRawImpliedGoto(ostream &s,const FlowBlock *nextBlock) const + +{ + if (sizeOut() != 1) return; + const FlowBlock *outBlock = getOut(0); + if (nextBlock->getType() != t_basic) { + nextBlock = nextBlock->getFrontLeaf(); + if (nextBlock == (const FlowBlock *)0) return; + nextBlock = nextBlock->subBlock(0); + } + if (getOut(0) == nextBlock) return; + if (!op.empty() && op.back()->isBranch()) return; + getStop().printRaw(s); + s << ": \t[ goto "; + outBlock->printShortHeader(s); + s << " ]" << endl; +} + /// \brief Check for values created in \b this block that flow outside the block. /// /// The block can calculate a value for a BRANCHIND or CBRANCH and can copy values and this method will still diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh index 1b3146ed2b..8319d83b9a 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh @@ -210,6 +210,14 @@ public: /// \param s is the given stream to write to virtual void printRaw(ostream &s) const {} + /// \brief If the \e out block of \b this is not the given next block, print an implied \b goto to the out block + /// + /// In order to see where \b this block is flowing to, if there is no explicit branch op, and if the next block + /// being printed is \e not the fallthru branch, print the destination block as an implied \b goto op. + /// \param s is the output stream + /// \param nextBlock is the given nextBlock being printed + virtual void printRawImpliedGoto(ostream &s,const FlowBlock *nextBlock) const {} + virtual void emit(PrintLanguage *lng) const; ///emitBlockGraph(this); } virtual PcodeOp *firstOp(void) const; virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const; @@ -473,6 +483,7 @@ public: virtual void decodeBody(Decoder &decoder); virtual void printHeader(ostream &s) const; virtual void printRaw(ostream &s) const; + virtual void printRawImpliedGoto(ostream &s,const FlowBlock *nextBlock) const; virtual void emit(PrintLanguage *lng) const { lng->emitBlockBasic(this); } virtual const FlowBlock *getExitLeaf(void) const { return this; } virtual PcodeOp *firstOp(void) const; @@ -515,6 +526,7 @@ public: virtual void printHeader(ostream &s) const; virtual void printTree(ostream &s,int4 level) const; virtual void printRaw(ostream &s) const { copy->printRaw(s); } + virtual void printRawImpliedGoto(ostream &s,const FlowBlock *nextBlock) const { copy->printRawImpliedGoto(s, nextBlock); } virtual void emit(PrintLanguage *lng) const { lng->emitBlockCopy(this); } virtual const FlowBlock *getExitLeaf(void) const { return this; } virtual PcodeOp *firstOp(void) const { return copy->firstOp(); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.cc index 56fcd00b48..c8acd865d3 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.cc @@ -2074,18 +2074,10 @@ bool ConditionalJoin::match(BlockBasic *b1,BlockBasic *b2) exita = (BlockBasic *)block1->getOut(0); exitb = (BlockBasic *)block1->getOut(1); if (exita == exitb) return false; - if (block2->getOut(0) == exita) { - if (block2->getOut(1) != exitb) return false; - a_in2 = block2->getOutRevIndex(0); - b_in2 = block2->getOutRevIndex(1); - } - else if (block2->getOut(0) == exitb) { - if (block2->getOut(1) != exita) return false; - a_in2 = block2->getOutRevIndex(1); - b_in2 = block2->getOutRevIndex(0); - } - else - return false; + if (block2->getOut(0) != exita) return false; // False exits must match + if (block2->getOut(1) != exitb) return false; // True exits must match + a_in2 = block2->getOutRevIndex(0); + b_in2 = block2->getOutRevIndex(1); a_in1 = block1->getOutRevIndex(0); b_in1 = block1->getOutRevIndex(1); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc index d8350e28b1..bb12d46769 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc @@ -591,7 +591,12 @@ void TypeOpBranch::printRaw(ostream &s,const PcodeOp *op) { s << name << ' '; - Varnode::printRaw(s,op->getIn(0)); + const BlockBasic *parent = op->getParent(); + if (parent != (const BlockBasic *)0 && parent->sizeOut() == 1) { + parent->getOut(0)->printShortHeader(s); + } + else + Varnode::printRaw(s,op->getIn(0)); } TypeOpCbranch::TypeOpCbranch(TypeFactory *t) : TypeOp(t,CPUI_CBRANCH,"goto") @@ -617,13 +622,25 @@ void TypeOpCbranch::printRaw(ostream &s,const PcodeOp *op) { s << name << ' '; - Varnode::printRaw(s,op->getIn(0)); // Print the distant (non-fallthru) destination + const BlockBasic *parent = op->getParent(); + FlowBlock *falseOut = (FlowBlock *)0; + if (parent != (const BlockBasic *)0 && parent->sizeOut() == 2) { + FlowBlock *trueOut = parent->getTrueOut(); + falseOut = parent->getFalseOut(); + trueOut->printShortHeader(s); + } + else + Varnode::printRaw(s,op->getIn(0)); // Print the distant (non-fallthru) destination s << " if ("; Varnode::printRaw(s,op->getIn(1)); - if (op->isBooleanFlip()^op->isFallthruTrue()) + if (op->isBooleanFlip()) s << " == 0)"; else s << " != 0)"; + if (falseOut != (FlowBlock *)0) { + s << " else "; + falseOut->printShortHeader(s); + } } TypeOpBranchind::TypeOpBranchind(TypeFactory *t) : TypeOp(t,CPUI_BRANCHIND,"switch")