diff --git a/Ghidra/Features/Decompiler/certification.manifest b/Ghidra/Features/Decompiler/certification.manifest index ccb91abf11..e3219bfa2b 100644 --- a/Ghidra/Features/Decompiler/certification.manifest +++ b/Ghidra/Features/Decompiler/certification.manifest @@ -43,6 +43,7 @@ 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/inlinetarget.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 61f484f738..bbe3028bf2 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/flow.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/flow.cc @@ -198,6 +198,19 @@ PcodeOp *FlowInfo::branchTarget(PcodeOp *op) const return target(addr); // Otherwise a normal address target } +/// Replace any reference to the op being inlined with the first op of the inlined sequence. +/// \param oldOp is the p-code op being inlined +/// \param newOp is the first p-code op in the inlined sequence +void FlowInfo::updateTarget(PcodeOp *oldOp,PcodeOp *newOp) + +{ + map::iterator viter = visited.find(oldOp->getAddr()); + if (viter != visited.end()) { // Check if -oldOp- is a possible branch target + if ((*viter).second.seqnum == oldOp->getSeqNum()) // (if injection op is the first op for its address) + (*viter).second.seqnum = newOp->getSeqNum(); // change the seqnum to the newOp + } +} + /// Check to see if the new target has been seen before. Otherwise /// add it to the list of addresses that need to be processed. /// Also check range bounds and update basic block information. @@ -1189,11 +1202,7 @@ void FlowInfo::doInjection(InjectPayload *payload,InjectContext &icontext,PcodeO obank.markIncidentalCopy(firstop, lastop); obank.moveSequenceDead(firstop,lastop,op); // Move the injection to right after the call - map::iterator viter = visited.find(op->getAddr()); - if (viter != visited.end()) { // Check if -op- is a possible branch target - if ((*viter).second.seqnum == op->getSeqNum()) // (if injection op is the first op for its address) - (*viter).second.seqnum = firstop->getSeqNum(); // change the seqnum to the first injected op - } + updateTarget(op,firstop); // Replace -op- with -firstop- in the target map // Get rid of the original call data.opDestroyRaw(op); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/flow.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/flow.hh index 4bd5743b0c..8f7bd48c75 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/flow.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/flow.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. @@ -148,6 +148,7 @@ public: void clearFlags(uint4 val) { flags &= ~val; } ///< Disable a specific option PcodeOp *target(const Address &addr) const; ///< Return first p-code op for instruction at given address PcodeOp *branchTarget(PcodeOp *op) const; ///< Find the target referred to by a given BRANCH or CBRANCH + void updateTarget(PcodeOp *oldOp,PcodeOp *newOp); ///< Update the branch target for an inlined p-code op void generateOps(void); ///< Generate raw control-flow from the function's base address void generateBlocks(void); ///< Generate basic blocks from the raw control-flow bool testHardInlineRestrictions(Funcdata *inlinefd,PcodeOp *op,Address &retaddr); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_op.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_op.cc index 24363d34b5..14ee7313ed 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_op.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_op.cc @@ -880,8 +880,10 @@ int4 Funcdata::inlineFlow(Funcdata *inlinefd,FlowInfo &flow,PcodeOp *callop) --oiter; PcodeOp *lastop = *oiter; obank.moveSequenceDead(firstop,lastop,callop); // Move cloned sequence to right after callop - if (callop->isBlockStart()) + if (callop->isBlockStart()) { firstop->setFlag(PcodeOp::startbasic); // First op of inline inherits callop's startbasic flag + flow.updateTarget(callop, firstop); + } else firstop->clearFlag(PcodeOp::startbasic); } diff --git a/Ghidra/Features/Decompiler/src/decompile/datatests/inlinetarget.xml b/Ghidra/Features/Decompiler/src/decompile/datatests/inlinetarget.xml new file mode 100644 index 0000000000..7d0b71bc13 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/datatests/inlinetarget.xml @@ -0,0 +1,35 @@ + + + + + 3821fff8 +95e10000960100044e800020 + + +85e1000086010004382100087c0803a6 +4e8000207c0802a64bffffd539e00000 +2c0f000a4080001c1e0f00047e100214 +7e0903a64e80042139ef00014280ffe4 +4280ffc0 + + + + + +Inlined function: prologue +Inlined function: epilogue +Could not find op at target +for \(iVar1 = 0; iVar1 < 10; iVar1 = iVar1 \+ 1\) + diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC64_ElfExtension.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC64_ElfExtension.java index 309c831db1..94dcb78471 100644 --- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC64_ElfExtension.java +++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC64_ElfExtension.java @@ -522,6 +522,7 @@ public class PowerPC64_ElfExtension extends ElfExtension { Function f = elfLoadHelper.createOneByteFunction(name, address, false); if (f != null && localFunction != null) { f.setThunkedFunction(localFunction); + elfLoadHelper.setElfSymbolAddress(elfSymbol, address); return null; // symbol creation handled } @@ -543,6 +544,11 @@ public class PowerPC64_ElfExtension extends ElfExtension { if (elf.e_machine() != ElfConstants.EM_PPC64) { return 0; } + + if (elf.getSection(".opd") != null) { + return 1; + } + // TODO: While the e_flags should indicate the use of function descriptors, this // may not be set reliably. The presence of the .opd section is another // indicator but could be missing if sections have been stripped. diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC64_ElfRelocationHandler.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC64_ElfRelocationHandler.java index f68f9740c0..9b640d7fe9 100644 --- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC64_ElfRelocationHandler.java +++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC64_ElfRelocationHandler.java @@ -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. @@ -215,27 +215,34 @@ public class PowerPC64_ElfRelocationHandler memory.setInt(relocationAddress, newValue); break; case R_PPC64_JMP_SLOT: - // TODO: do we need option to allow function descriptor - // use - or not? The EF_PPC64_ABI in e_flags is not reliable. - Address functionDescriptorAddr = relocationAddress.getNewAddress(symbolValue); - MemoryBlock block = memory.getBlock(functionDescriptorAddr); + MemoryBlock block = memory.getBlock(symbolAddr); if (block == null) { throw new MemoryAccessException( - "Function descriptor not found at: " + functionDescriptorAddr); + "Relocation symbol not found in memory: " + symbolAddr); } + if (MemoryBlock.EXTERNAL_BLOCK_NAME.equals(block.getName())) { // If symbol is in EXTERNAL block, we don't have descriptor entry; // just fill-in first slot with EXTERNAL address memory.setLong(relocationAddress, symbolValue); byteLength = 8; + break; } - else { + + if (PowerPC64_ElfExtension + .getPpc64ABIVersion(elfRelocationContext.getElfHeader()) == 1) { + // ABI ELFv1 (used by big-endian PPC64) expected to copy full function descriptor + // into .got.plt section where symbolAddr refers to function descriptor // Copy function descriptor data - byte[] bytes = new byte[24]; // TODO: can descriptor size vary ? - memory.getBytes(functionDescriptorAddr, bytes); + byte[] bytes = new byte[24]; + memory.getBytes(symbolAddr, bytes); memory.setBytes(relocationAddress, bytes); byteLength = bytes.length; } + else { + memory.setLong(relocationAddress, symbolValue); + byteLength = 8; + } break; case R_PPC64_UADDR32: newValue = (int) (symbolValue + addend);