diff --git a/Ghidra/Features/Decompiler/certification.manifest b/Ghidra/Features/Decompiler/certification.manifest index ce36ce2ddb..2e4307fb1b 100644 --- a/Ghidra/Features/Decompiler/certification.manifest +++ b/Ghidra/Features/Decompiler/certification.manifest @@ -38,6 +38,7 @@ src/decompile/datatests/ifswitch.xml||GHIDRA||||END| src/decompile/datatests/impliedfield.xml||GHIDRA||||END| src/decompile/datatests/indproto.xml||GHIDRA||||END| src/decompile/datatests/injectoverride.xml||GHIDRA||||END| +src/decompile/datatests/inline.xml||GHIDRA||||END| src/decompile/datatests/longdouble.xml||GHIDRA||||END| src/decompile/datatests/loopcomment.xml||GHIDRA||||END| src/decompile/datatests/lzcount.xml||GHIDRA||||END| diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/flow.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/flow.cc index 00651c18e6..61f484f738 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/flow.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/flow.cc @@ -1120,12 +1120,6 @@ void FlowInfo::inlineEZClone(const FlowInfo &inlineflow,const Address &calladdr) bool FlowInfo::testHardInlineRestrictions(Funcdata *inlinefd,PcodeOp *op,Address &retaddr) { - if (inline_recursion->find( inlinefd->getAddress() ) != inline_recursion->end()) { - // This function has already been included with current inlining - inline_head->warning("Could not inline here",op->getAddr()); - return false; - } - if (!inlinefd->getFuncProto().isNoReturn()) { list::iterator iter = op->getInsertIter(); ++iter; @@ -1142,8 +1136,6 @@ bool FlowInfo::testHardInlineRestrictions(Funcdata *inlinefd,PcodeOp *op,Address // If the inlining "jumps back" this starts a new basic block data.opMarkStartBasic(nextop); } - - inline_recursion->insert(inlinefd->getAddress()); return true; } @@ -1243,11 +1235,31 @@ bool FlowInfo::inlineSubFunction(FuncCallSpecs *fc) { Funcdata *fd = fc->getFuncdata(); if (fd == (Funcdata *)0) return false; - PcodeOp *op = fc->getOp(); - Address retaddr; - if (!data.inlineFlow( fd, *this, op)) + if (inline_head == (Funcdata *)0) { + // This is the top level of inlining + inline_head = &data; // Set up head of inlining + inline_recursion = &inline_base; + } + inline_recursion->insert(data.getAddress()); // Insert current function + if (inline_recursion->find( fd->getAddress() ) != inline_recursion->end()) { + // This function has already been included with current inlining + inline_head->warning("Could not inline here",fc->getOp()->getAddr()); return false; + } + + int4 res = data.inlineFlow( fd, *this, fc->getOp()); + if (res < 0) + return false; + else if (res == 0) { // easy model + // Remove inlined function from list so it can be inlined again, even if it also inlines + inline_recursion->erase(fd->getAddress()); + } + else if (res == 1) { // hard model + // Add inlined function to recursion list, even if it contains no inlined calls, + // to prevent parent from inlining it twice + inline_recursion->insert(fd->getAddress()); + } // Changing CALL to JUMP may make some original code unreachable setPossibleUnreachable(); @@ -1306,17 +1318,6 @@ void FlowInfo::deleteCallSpec(FuncCallSpecs *fc) void FlowInfo::injectPcode(void) { - if (inline_head == (Funcdata *)0) { - // This is the top level of inlining - inline_head = &data; // Set up head of inlining - inline_recursion = &inline_base; - inline_recursion->insert(data.getAddress()); // Insert ourselves - // inline_head = (Funcdata *)0; - } - else { - inline_recursion->insert(data.getAddress()); // Insert ourselves - } - for(int4 i=0;i::iterator pos); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_op.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_op.cc index c2dc6be72b..1da5e2acb3 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_op.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_op.cc @@ -804,8 +804,8 @@ void Funcdata::truncatedFlow(const Funcdata *fd,const FlowInfo *flow) /// \param inlinefd is the function to in-line /// \param flow is the flow object being injected /// \param callop is the site of the injection -/// \return \b true if the injection was successful -bool Funcdata::inlineFlow(Funcdata *inlinefd,FlowInfo &flow,PcodeOp *callop) +/// \return 0 for a successful inlining with the easy model, 1 for the hard model, -1 if inlining was not successful +int4 Funcdata::inlineFlow(Funcdata *inlinefd,FlowInfo &flow,PcodeOp *callop) { inlinefd->getArch()->clearAnalysis(inlinefd); @@ -821,7 +821,9 @@ bool Funcdata::inlineFlow(Funcdata *inlinefd,FlowInfo &flow,PcodeOp *callop) inlineflow.forwardRecursion(flow); inlineflow.generateOps(); + int4 res; if (inlineflow.checkEZModel()) { + res = 0; // With an EZ clone there are no jumptables to clone list::const_iterator oiter = obank.endDead(); --oiter; // There is at least one op @@ -843,7 +845,8 @@ bool Funcdata::inlineFlow(Funcdata *inlinefd,FlowInfo &flow,PcodeOp *callop) else { Address retaddr; if (!flow.testHardInlineRestrictions(inlinefd,callop,retaddr)) - return false; + return -1; + res = 1; vector::const_iterator jiter; // Clone any jumptables from inline piece for(jiter=inlinefd->jumpvec.begin();jiter!=inlinefd->jumpvec.end();++jiter) { JumpTable *jtclone = new JumpTable(*jiter); @@ -862,7 +865,7 @@ bool Funcdata::inlineFlow(Funcdata *inlinefd,FlowInfo &flow,PcodeOp *callop) obank.setUniqId( inlinefd->obank.getUniqId() ); - return true; + return res; } /// \brief Find the primary branch operation for an instruction diff --git a/Ghidra/Features/Decompiler/src/decompile/datatests/inline.xml b/Ghidra/Features/Decompiler/src/decompile/datatests/inline.xml new file mode 100644 index 0000000000..de10f1608c --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/datatests/inline.xml @@ -0,0 +1,63 @@ + + + + +8d4732c3e8f7ffffff89c7e8f0ffffff +c339f77c01c34883ec084889d7e8de0f +00004883c408c35389fbba88001000be +0a000000e8d8ffffffba8c001000be64 +00000089dfe8c7ffffff5bc34883ec08 +85f6751389f8c1e81f01c7d1ffe80b00 +00004883c408c38d7c7f01ebf089f883 +ff0174134883ec0889fe83e601e8caff +ffff4883c408c3c3 + + + 54454e0048554e4452454400 + + + + + + + + + + +return a \+ 100; +if \(x < 10\) +puts\("TEN"\); +compare\(x,100,"HUNDRED"\); +if \(\(val & 1U\) +val = val / 2; +val = val \* 3 \+ 1; += collatz\(val\); +WARNING: Could not inline here +WARNING: Inlined function: add50 +WARNING: Inlined function: compare +WARNING: Inlined function: collatz1 +