From e5969a613cdca59252cc0366254d005597c313a2 Mon Sep 17 00:00:00 2001 From: caheckman <48068198+caheckman@users.noreply.github.com> Date: Fri, 23 Aug 2024 00:11:47 +0000 Subject: [PATCH] GP-4871 Don't ignore signed to unsigned integer casts for FLOAT_INT2FLOAT --- .../Decompiler/certification.manifest | 1 + .../src/decompile/cpp/architecture.cc | 2 +- .../Decompiler/src/decompile/cpp/block.cc | 35 ++++- .../Decompiler/src/decompile/cpp/block.hh | 5 +- .../src/decompile/cpp/coreaction.cc | 8 ++ .../Decompiler/src/decompile/cpp/fspec.cc | 20 ++- .../Decompiler/src/decompile/cpp/printc.cc | 13 ++ .../Decompiler/src/decompile/cpp/printc.hh | 6 +- .../src/decompile/cpp/ruleaction.cc | 130 ++++++++++++++++++ .../src/decompile/cpp/ruleaction.hh | 22 +++ .../Decompiler/src/decompile/cpp/subflow.cc | 51 +++++++ .../Decompiler/src/decompile/cpp/subflow.hh | 4 +- .../src/decompile/cpp/testfunction.cc | 12 +- .../Decompiler/src/decompile/cpp/typeop.cc | 57 ++++++++ .../Decompiler/src/decompile/cpp/typeop.hh | 3 + .../src/decompile/datatests/floatconv.xml | 55 ++++++++ 16 files changed, 408 insertions(+), 16 deletions(-) create mode 100644 Ghidra/Features/Decompiler/src/decompile/datatests/floatconv.xml diff --git a/Ghidra/Features/Decompiler/certification.manifest b/Ghidra/Features/Decompiler/certification.manifest index 6cb15d2b66..8e397e6d58 100644 --- a/Ghidra/Features/Decompiler/certification.manifest +++ b/Ghidra/Features/Decompiler/certification.manifest @@ -25,6 +25,7 @@ src/decompile/datatests/doublemove.xml||GHIDRA||||END| src/decompile/datatests/dupptr.xml||GHIDRA||||END| src/decompile/datatests/elseif.xml||GHIDRA||||END| src/decompile/datatests/floatcast.xml||GHIDRA||||END| +src/decompile/datatests/floatconv.xml||GHIDRA||||END| src/decompile/datatests/floatprint.xml||GHIDRA||||END| src/decompile/datatests/forloop1.xml||GHIDRA||||END| src/decompile/datatests/forloop_loaditer.xml||GHIDRA||||END| diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc index 841e9ec22d..494d160db8 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc @@ -33,7 +33,7 @@ using std::sqrt; vector ArchitectureCapability::thelist; const uint4 ArchitectureCapability::majorversion = 6; -const uint4 ArchitectureCapability::minorversion = 0; +const uint4 ArchitectureCapability::minorversion = 1; AttributeId ATTRIB_ADDRESS = AttributeId("address",148); AttributeId ATTRIB_ADJUSTVMA = AttributeId("adjustvma",103); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc index 7d783e7884..a24283890b 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc @@ -5,9 +5,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. @@ -814,6 +814,37 @@ FlowBlock *FlowBlock::findCommonBlock(const vector &blockSet) return res; } +/// \brief Find conditional block that decides between the given control-flow edges +/// +/// There must be a unique path from the conditional block through the first edge, and +/// a second unique path through the second edge. Otherwise null is returned. The index of the +/// output block from the conditional that flows to the first edge is passed back. +/// \param bl1 is the destination block for the first given control-flow edge +/// \param edge1 is the input slot for the first edge +/// \param bl2 is the destination block for the second given control-flow edge +/// \param edge2 is the input slot for the second edge +/// \param slot1 will hold the output slot leading to the first control-flow edge +/// \return the conditional FlowBlock if it exists or null +FlowBlock *FlowBlock::findCondition(FlowBlock *bl1,int4 edge1,FlowBlock *bl2,int4 edge2,int4 &slot1) + +{ + FlowBlock *cond = bl1->getIn(edge1); + while (cond->sizeOut() != 2) { + if (cond->sizeOut() != 1) return (FlowBlock *)0; + bl1 = cond; + edge1 = 0; + cond = bl1->getIn(0); + } + + while (cond != bl2->getIn(edge2)) { + bl2 = bl2->getIn(edge2); + if (bl2->sizeOut() != 1) return (FlowBlock *)0; + edge2 = 0; + } + slot1 = bl1->getInRevIndex(edge1); + return cond; +} + /// Add the given FlowBlock to the list and make \b this the parent /// Update \b index so that it has the minimum over all components /// \param bl is the given FlowBlock diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh index aade37d7e6..d43b07ed3d 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/block.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. @@ -344,6 +344,7 @@ public: static bool compareFinalOrder(const FlowBlock *bl1,const FlowBlock *bl2); ///< Final FlowBlock comparison static FlowBlock *findCommonBlock(FlowBlock *bl1,FlowBlock *bl2); ///< Find the common dominator of two FlowBlocks static FlowBlock *findCommonBlock(const vector &blockSet); ///< Find common dominator of multiple FlowBlocks + static FlowBlock *findCondition(FlowBlock *bl1,int4 edge1,FlowBlock *bl2,int4 edge2,int4 &slot1); }; /// \brief A control-flow block built out of sub-components diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc index d8a2140dd3..a75a5e5929 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc @@ -3776,6 +3776,12 @@ void ActionDeadCode::propagateConsumed(vector &worklist) case CPUI_CALL: case CPUI_CALLIND: break; // Call output doesn't indicate consumption of inputs + case CPUI_FLOAT_INT2FLOAT: + a = 0; + if (outc != 0) + a = coveringmask(op->getIn(0)->getNZMask()); + pushConsumed(a,op->getIn(0), worklist); + break; default: a = (outc==0) ? 0 : ~((uintb)0); // all or nothing for(int4 i=0;inumInput();++i) @@ -5538,6 +5544,8 @@ void ActionDatabase::universalAction(Architecture *conf) actprop->addRule( new RuleSubfloatConvert("floatprecision") ); actprop->addRule( new RuleFloatCast("floatprecision") ); actprop->addRule( new RuleIgnoreNan("floatprecision") ); + actprop->addRule( new RuleUnsigned2Float("analysis") ); + actprop->addRule( new RuleInt2FloatCollapse("analysis") ); actprop->addRule( new RulePtraddUndo("typerecovery") ); actprop->addRule( new RulePtrsubUndo("typerecovery") ); actprop->addRule( new RuleSegment("segment") ); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc index a027b242a0..6ebec206c9 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc @@ -3105,6 +3105,8 @@ ProtoParameter *ProtoStoreSymbol::setInput(int4 i, const string &nm,const Parame bool isindirect = (pieces.flags & ParameterPieces::indirectstorage) != 0; bool ishidden = (pieces.flags & ParameterPieces::hiddenretparm) != 0; + bool istypelock = (pieces.flags & ParameterPieces::typelock) != 0; + bool isnamelock = (pieces.flags & ParameterPieces::namelock) != 0; if (res->sym != (Symbol *)0) { entry = res->sym->getFirstWholeMap(); if ((entry->getAddr() != pieces.addr)||(entry->getSize() != pieces.type->getSize())) { @@ -3117,12 +3119,16 @@ ProtoParameter *ProtoStoreSymbol::setInput(int4 i, const string &nm,const Parame usepoint = restricted_usepoint; res->sym = scope->addSymbol(nm,pieces.type,pieces.addr,usepoint)->getSymbol(); scope->setCategory(res->sym,Symbol::function_parameter,i); - if (isindirect || ishidden) { + if (isindirect || ishidden || istypelock || isnamelock) { uint4 mirror = 0; if (isindirect) mirror |= Varnode::indirectstorage; if (ishidden) mirror |= Varnode::hiddenretparm; + if (istypelock) + mirror |= Varnode::typelock; + if (isnamelock) + mirror |= Varnode::namelock; scope->setAttribute(res->sym,mirror); } return res; @@ -3139,6 +3145,18 @@ ProtoParameter *ProtoStoreSymbol::setInput(int4 i, const string &nm,const Parame else scope->clearAttribute(res->sym,Varnode::hiddenretparm); } + if (res->sym->isTypeLocked() != istypelock) { + if (istypelock) + scope->setAttribute(res->sym,Varnode::typelock); + else + scope->clearAttribute(res->sym,Varnode::typelock); + } + if (res->sym->isNameLocked() != isnamelock) { + if (isnamelock) + scope->setAttribute(res->sym,Varnode::namelock); + else + scope->clearAttribute(res->sym,Varnode::namelock); + } if ((nm.size()!=0)&&(nm!=res->sym->getName())) scope->renameSymbol(res->sym,nm); if (pieces.type != res->sym->getType()) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc index 6042986698..0e595426ac 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc @@ -827,6 +827,19 @@ void PrintC::opBoolNegate(const PcodeOp *op) } } +void PrintC::opFloatInt2Float(const PcodeOp *op) + +{ + const PcodeOp *zextOp = TypeOpFloatInt2Float::absorbZext(op); + const Varnode *vn0 = (zextOp != (const PcodeOp *)0) ? zextOp->getIn(0) : op->getIn(0); + Datatype *dt = op->getOut()->getHighTypeDefFacing(); + if (!option_nocasts) { + pushOp(&typecast,op); + pushType(dt); + } + pushVn(vn0,op,mods); +} + void PrintC::opSubpiece(const PcodeOp *op) { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh index 3cebbc3f91..380624335a 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.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. @@ -322,7 +322,7 @@ public: virtual void opFloatNeg(const PcodeOp *op) { opUnary(&unary_minus,op); } virtual void opFloatAbs(const PcodeOp *op) { opFunc(op); } virtual void opFloatSqrt(const PcodeOp *op) { opFunc(op); } - virtual void opFloatInt2Float(const PcodeOp *op) { opTypeCast(op); } + virtual void opFloatInt2Float(const PcodeOp *op); virtual void opFloatFloat2Float(const PcodeOp *op) { opTypeCast(op); } virtual void opFloatTrunc(const PcodeOp *op) { opTypeCast(op); } virtual void opFloatCeil(const PcodeOp *op) { opFunc(op); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc index 7dab24a8c3..2242468e6e 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc @@ -9801,6 +9801,136 @@ int4 RuleIgnoreNan::applyOp(PcodeOp *op,Funcdata &data) return (count > 0) ? 1 : 0; } +/// \class RuleUnsigned2Float +/// \brief Simplify conversion: `T = int2float((X >> 1) | X & #1); T + T => int2float( zext(X) )` +/// +/// Architectures like x86 can use this sequence to simulate an unsigned integer to floating-point conversion, +/// when they don't have the conversion in hardware. +void RuleUnsigned2Float::getOpList(vector &oplist) const + +{ + oplist.push_back(CPUI_FLOAT_INT2FLOAT); +} + +int4 RuleUnsigned2Float::applyOp(PcodeOp *op,Funcdata &data) + +{ + Varnode *invn = op->getIn(0); + if (!invn->isWritten()) return 0; + PcodeOp *orop = invn->getDef(); + if (orop->code() != CPUI_INT_OR) return 0; + if (!orop->getIn(0)->isWritten() || !orop->getIn(1)->isWritten()) return 0; + PcodeOp *shiftop = orop->getIn(0)->getDef(); + PcodeOp *andop; + if (shiftop->code() != CPUI_INT_RIGHT) { + andop = shiftop; + shiftop = orop->getIn(1)->getDef(); + } + else { + andop = orop->getIn(1)->getDef(); + } + if (shiftop->code() != CPUI_INT_RIGHT) return 0; + if (!shiftop->getIn(1)->constantMatch(1)) return 0; // Shift to right by 1 exactly to clear high-bit + Varnode *basevn = shiftop->getIn(0); + if (basevn->isFree()) return 0; + if (andop->code() == CPUI_INT_ZEXT) { + if (!andop->getIn(0)->isWritten()) return 0; + andop = andop->getIn(0)->getDef(); + } + if (andop->code() != CPUI_INT_AND) return 0; + if (!andop->getIn(1)->constantMatch(1)) return 0; // Mask off least significant bit + Varnode *vn = andop->getIn(0); + if (basevn != vn) { + if (!vn->isWritten()) return 0; + PcodeOp *subop = vn->getDef(); + if (subop->code() != CPUI_SUBPIECE) return 0; + if (subop->getIn(1)->getOffset() != 0) return 0; + vn = subop->getIn(0); + if (basevn != vn) return 0; + } + Varnode *outvn = op->getOut(); + list::const_iterator iter; + for(iter=outvn->beginDescend();iter!=outvn->endDescend();++iter) { + PcodeOp *addop = *iter; + if (addop->code() != CPUI_FLOAT_ADD) continue; + if (addop->getIn(0) != outvn) continue; + if (addop->getIn(1) != outvn) continue; + PcodeOp *zextop = data.newOp(1,addop->getAddr()); + data.opSetOpcode(zextop, CPUI_INT_ZEXT); + Varnode *zextout = data.newUniqueOut(TypeOpFloatInt2Float::preferredZextSize(basevn->getSize()), zextop); + data.opSetOpcode(addop, CPUI_FLOAT_INT2FLOAT); + data.opRemoveInput(addop, 1); + data.opSetInput(zextop, basevn, 0); + data.opSetInput(addop, zextout, 0); + data.opInsertBefore(zextop, addop); + return 1; + } + return 0; +} + +/// \class RuleInt2FloatCollapse +/// \brief Collapse equivalent FLOAT_INT2FLOAT computations along converging data-flow paths +/// +/// Look for two code paths with different ways of calculating an unsigned integer to floating-point conversion, +/// one of which is chosen by examining the most significant bit of the integer. The two paths can be collapsed +/// into a single FLOAT_INT2FLOAT operation. +void RuleInt2FloatCollapse::getOpList(vector &oplist) const + +{ + oplist.push_back(CPUI_FLOAT_INT2FLOAT); +} + +int4 RuleInt2FloatCollapse::applyOp(PcodeOp *op,Funcdata &data) + +{ + if (!op->getIn(0)->isWritten()) return 0; + PcodeOp *zextop = op->getIn(0)->getDef(); + if (zextop->code() != CPUI_INT_ZEXT) return 0; // Original FLOAT_INT2FLOAT must be unsigned form + Varnode *basevn = zextop->getIn(0); + if (basevn->isFree()) return 0; + PcodeOp *multiop = op->getOut()->loneDescend(); + if (multiop == (PcodeOp *)0) return 0; + if (multiop->code() != CPUI_MULTIEQUAL) return 0; // Output comes together with 1 other flow + if (multiop->numInput() != 2) return 0; + int4 slot = multiop->getSlot(op->getOut()); + Varnode *otherout = multiop->getIn(1-slot); + if (!otherout->isWritten()) return 0; + PcodeOp *op2 = otherout->getDef(); + if (op2->code() != CPUI_FLOAT_INT2FLOAT) return 0; // The other flow must be a signed FLOAT_INT2FLOAT + if (basevn != op2->getIn(0)) return 0; // taking the same input + int4 dir2unsigned; // Control path to unsigned conversion + FlowBlock *cond = FlowBlock::findCondition(multiop->getParent(), slot, multiop->getParent(), 1-slot, dir2unsigned); + if (cond == (FlowBlock *)0) return 0; + PcodeOp *cbranch = cond->lastOp(); + if (cbranch == (PcodeOp *)0 || cbranch->code() != CPUI_CBRANCH) return 0; + if (!cbranch->getIn(1)->isWritten()) return 0; + if (cbranch->isBooleanFlip()) return 0; + PcodeOp *compare = cbranch->getIn(1)->getDef(); + if (compare->code() != CPUI_INT_SLESS) return 0; + if (compare->getIn(1)->constantMatch(0)) { // If condition is (basevn < 0) + if (compare->getIn(0) != basevn) return 0; + if (dir2unsigned != 1) return 0; // True branch must be the unsigned FLOAT_INT2FLOAT + } + else if (compare->getIn(0)->constantMatch(calc_mask(basevn->getSize()))) { // If condition is (-1 < basevn) + if (compare->getIn(1) != basevn) return 0; + if (dir2unsigned == 1) return 0; // True branch must be to signed FLOAT_INT2FLOAT + } + else + return 0; + BlockBasic *outbl = multiop->getParent(); + data.opUninsert(multiop); + data.opSetOpcode(multiop, CPUI_FLOAT_INT2FLOAT); // Redefine the MULTIEQUAL as unsigned FLOAT_INT2FLOAT + data.opRemoveInput(multiop, 0); + PcodeOp *newzext = data.newOp(1, multiop->getAddr()); + data.opSetOpcode(newzext, CPUI_INT_ZEXT); + Varnode *newout = data.newUniqueOut(TypeOpFloatInt2Float::preferredZextSize(basevn->getSize()), newzext); + data.opSetInput(newzext,basevn,0); + data.opSetInput(multiop, newout, 0); + data.opInsertBegin(multiop, outbl); // Reinsert modified MULTIEQUAL after any other MULTIEQUAL + data.opInsertBefore(newzext, multiop); + return 1; +} + /// \class RuleFuncPtrEncoding /// \brief Eliminate ARM/THUMB style masking of the low order bits on function pointers /// diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.hh index 377ab54039..5ba53e68de 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.hh @@ -1568,6 +1568,28 @@ public: virtual int4 applyOp(PcodeOp *op,Funcdata &data); }; +class RuleUnsigned2Float : public Rule { +public: + RuleUnsigned2Float(const string &g) : Rule( g, 0, "unsigned2float") {} ///< Constructor + virtual Rule *clone(const ActionGroupList &grouplist) const { + if (!grouplist.contains(getGroup())) return (Rule *)0; + return new RuleUnsigned2Float(getGroup()); + } + virtual void getOpList(vector &oplist) const; + virtual int4 applyOp(PcodeOp *op,Funcdata &data); +}; + +class RuleInt2FloatCollapse : public Rule { +public: + RuleInt2FloatCollapse(const string &g) : Rule( g, 0, "int2floatcollapse") {} ///< Constructor + virtual Rule *clone(const ActionGroupList &grouplist) const { + if (!grouplist.contains(getGroup())) return (Rule *)0; + return new RuleInt2FloatCollapse(getGroup()); + } + virtual void getOpList(vector &oplist) const; + virtual int4 applyOp(PcodeOp *op,Funcdata &data); +}; + class RuleFuncPtrEncoding : public Rule { public: RuleFuncPtrEncoding(const string &g) : Rule( g, 0, "funcptrencoding") {} ///< Constructor diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/subflow.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/subflow.cc index b6f930210c..bcdccecfca 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/subflow.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/subflow.cc @@ -330,6 +330,41 @@ bool SubvariableFlow::trySwitchPull(PcodeOp *op,ReplaceVarnode *rvn) return true; } +/// \brief Determine if the subgraph variable flows naturally into a terminal FLOAT_INT2FLOAT operation +/// +/// The original data-flow must pad the logical value with zero bits, making the conversion to +/// floating-point unsigned. A PatchRecord is created that preserves the FLOAT_INT2FLOAT but inserts an +/// additional INT_ZEXT operation to preserve the unsigned nature of the conversion. +/// \param op is the FLOAT_INT2FLOAT conversion operation +/// \param rvn is the logical value flowing into the conversion +bool SubvariableFlow::tryInt2FloatPull(PcodeOp *op,ReplaceVarnode *rvn) + +{ + if ((rvn->mask & 1) == 0) return false; // Logical value must be justified + if ((rvn->vn->getNZMask()&~rvn->mask)!=0) + return false; // Everything outside the logical value must be zero + if (rvn->vn->getSize() == flowsize) + return false; // There must be some (zero) extension + bool pullModification = true; + if (rvn->vn->isWritten() && rvn->vn->getDef()->code() == CPUI_INT_ZEXT) { + if (rvn->vn->getSize() == TypeOpFloatInt2Float::preferredZextSize(flowsize)) { + if (rvn->vn->loneDescend() == op) { + pullModification = false; // This patch does not count as a modification + // The INT_ZEXT -> FLOAT_INT2FLOAT has the correct form and does not need to be modified. + // We indicate this by NOT incrementing pullcount, so there has to be at least one other + // terminal patch in order for doTrace() to return true. + } + } + } + patchlist.emplace_back(); + patchlist.back().type = PatchRecord::int2float_patch; + patchlist.back().patchOp = op; + patchlist.back().in1 = rvn; + if (pullModification) + pullcount += 1; + return true; +} + /// Try to trace the logical variable through descendant Varnodes /// creating new nodes in the logical subgraph and updating the worklist. /// \param rvn is the given subgraph variable to trace @@ -586,6 +621,10 @@ bool SubvariableFlow::traceForward(ReplaceVarnode *rvn) if (rvn->mask != 1) return false; addBooleanPatch(op,rvn,slot); break; + case CPUI_FLOAT_INT2FLOAT: + if (!tryInt2FloatPull(op, rvn)) return false; + hcount += 1; + break; case CPUI_CBRANCH: if ((bitsize != 1)||(slot != 1)) return false; if (rvn->mask != 1) return false; @@ -1451,6 +1490,18 @@ void SubvariableFlow::doReplacement(void) } case PatchRecord::push_patch: break; // Shouldn't see these here, handled earlier + case PatchRecord::int2float_patch: + { + PcodeOp *zextOp = fd->newOp(1, pullop->getAddr()); + fd->opSetOpcode(zextOp, CPUI_INT_ZEXT); + Varnode *invn = getReplaceVarnode((*piter).in1); + fd->opSetInput(zextOp,invn,0); + int4 sizeout = TypeOpFloatInt2Float::preferredZextSize(invn->getSize()); + Varnode *outvn = fd->newUniqueOut(sizeout, zextOp); + fd->opInsertBefore(zextOp, pullop); + fd->opSetInput(pullop, outvn, 0); + break; + } } } } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/subflow.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/subflow.hh index 06b11cc92f..0f54a624b2 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/subflow.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/subflow.hh @@ -70,7 +70,8 @@ class SubvariableFlow { compare_patch, ///< Turn compare op inputs into logical values parameter_patch, ///< Convert a CALL/CALLIND/RETURN/BRANCHIND parameter into logical value extension_patch, ///< Convert op into something that copies/extends logical value, adding zero bits - push_patch ///< Convert an operator output to the logical value + push_patch, ///< Convert an operator output to the logical value + int2float_patch ///< Zero extend logical value into FLOAT_INT2FLOAT operator }; patchtype type; ///< The type of \b this patch PcodeOp *patchOp; ///< Op being affected @@ -101,6 +102,7 @@ class SubvariableFlow { bool tryReturnPull(PcodeOp *op,ReplaceVarnode *rvn,int4 slot); bool tryCallReturnPush(PcodeOp *op,ReplaceVarnode *rvn); bool trySwitchPull(PcodeOp *op,ReplaceVarnode *rvn); + bool tryInt2FloatPull(PcodeOp *op,ReplaceVarnode *rvn); bool traceForward(ReplaceVarnode *rvn); ///< Trace the logical data-flow forward for the given subgraph variable bool traceBackward(ReplaceVarnode *rvn); ///< Trace the logical data-flow backward for the given subgraph variable bool traceForwardSext(ReplaceVarnode *rvn); ///< Trace logical data-flow forward assuming sign-extensions diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/testfunction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/testfunction.cc index a0fba842c4..c8e43af58a 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/testfunction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/testfunction.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. @@ -267,14 +267,14 @@ void FunctionTestCollection::restoreXml(DocumentStorage &store,const Element *el buildProgram(store); } else - throw IfaceParseError("Unknown tag in : "+subel->getName()); + throw IfaceParseError("Unknown tag in : "+subel->getName()); } if (!sawScript) - throw IfaceParseError("Did not see +return \(float4\)\(int4\)\(fval - 0x10\) \* -0.001; +return \(float8\)\(lval - 0x10\) \* -0.001; +return \(float8\)\(llval - 0x10\) \* -0.001; +