mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-09-20 09:31:47 +00:00
GP-4871 Don't ignore signed to unsigned integer casts for
FLOAT_INT2FLOAT
This commit is contained in:
parent
a4d97ff872
commit
e5969a613c
|
@ -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|
|
||||
|
|
|
@ -33,7 +33,7 @@ using std::sqrt;
|
|||
vector<ArchitectureCapability *> 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);
|
||||
|
|
|
@ -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<FlowBlock *> &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
|
||||
|
|
|
@ -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<FlowBlock *> &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
|
||||
|
|
|
@ -3776,6 +3776,12 @@ void ActionDeadCode::propagateConsumed(vector<Varnode *> &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;i<op->numInput();++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") );
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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)
|
||||
|
||||
{
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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<uint4> &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<PcodeOp *>::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<uint4> &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
|
||||
///
|
||||
|
|
|
@ -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<uint4> &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<uint4> &oplist) const;
|
||||
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
||||
};
|
||||
|
||||
class RuleFuncPtrEncoding : public Rule {
|
||||
public:
|
||||
RuleFuncPtrEncoding(const string &g) : Rule( g, 0, "funcptrencoding") {} ///< Constructor
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <decompiletest>: "+subel->getName());
|
||||
throw IfaceParseError("Unknown tag in <decompilertest>: "+subel->getName());
|
||||
}
|
||||
if (!sawScript)
|
||||
throw IfaceParseError("Did not see <script> tag in <decompiletest>");
|
||||
throw IfaceParseError("Did not see <script> tag in <decompilertest>");
|
||||
if (!sawTests)
|
||||
throw IfaceParseError("Did not see any <stringmatch> tags in <decompiletest>");
|
||||
throw IfaceParseError("Did not see any <stringmatch> tags in <decompilertest>");
|
||||
if (!sawProgram)
|
||||
throw IfaceParseError("No <binaryimage> tag in <decompiletest>");
|
||||
throw IfaceParseError("No <binaryimage> tag in <decompilertest>");
|
||||
}
|
||||
|
||||
/// Pull the script and tests from a comment in \<binaryimage>
|
||||
|
|
|
@ -1784,6 +1784,63 @@ TypeOpFloatInt2Float::TypeOpFloatInt2Float(TypeFactory *t,const Translate *trans
|
|||
behave = new OpBehaviorFloatInt2Float(trans);
|
||||
}
|
||||
|
||||
Datatype *TypeOpFloatInt2Float::getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const
|
||||
|
||||
{
|
||||
if (absorbZext(op) != (const PcodeOp *)0)
|
||||
return (Datatype *)0; // No cast if we are absorbing an INT_ZEXT
|
||||
const Varnode *vn = op->getIn(slot);
|
||||
Datatype *reqtype = op->inputTypeLocal(slot);
|
||||
Datatype *curtype = vn->getHighTypeReadFacing(op);
|
||||
bool care_uint_int = true;
|
||||
if (vn->getSize() <= sizeof(uintb)) {
|
||||
uintb val = vn->getNZMask();
|
||||
val >>= (8*vn->getSize() - 1);
|
||||
care_uint_int = (val & 1) != 0; // If the high-bit is not set, we don't care if input is signed or unsigned
|
||||
}
|
||||
return castStrategy->castStandard(reqtype,curtype,care_uint_int,true);
|
||||
}
|
||||
|
||||
/// \brief Return any INT_ZEXT PcodeOp that the given FLOAT_INT2FLOAT absorbs
|
||||
///
|
||||
/// FLOAT_INT2FLOAT expects a signed integer input, but if the input is produced by an INT_ZEXT, we treat
|
||||
/// the FLOAT_INT2FLOAT as a conversion of the unsigned integer input to the INT_ZEXT and effectively
|
||||
/// absorb the extension operation into the FLOAT_INT2FLOAT operation. If this is happening, the specific
|
||||
/// INT_ZEXT operation is returned, otherwise null is returned.
|
||||
/// \param op is the given FLOAT_INT2FLOAT
|
||||
/// \return the absorbed INT_ZEXT or null
|
||||
const PcodeOp *TypeOpFloatInt2Float::absorbZext(const PcodeOp *op)
|
||||
|
||||
{
|
||||
const Varnode *vn0 = op->getIn(0);
|
||||
if (vn0->isWritten() && vn0->isImplied()) {
|
||||
const PcodeOp *zextOp = vn0->getDef();
|
||||
if (zextOp->code() == CPUI_INT_ZEXT) {
|
||||
return zextOp;
|
||||
}
|
||||
}
|
||||
return (const PcodeOp *)0;
|
||||
}
|
||||
|
||||
/// \brief Return the preferred extension size for passing a an unsigned value to FLOAT_INT2FLOAT
|
||||
///
|
||||
/// FLOAT_INT2FLOAT expects a signed input but can be used for unsigned conversion by first zero extending
|
||||
/// the value to be converted. This method returns the preferred output size for this extension.
|
||||
/// \param inSize is the size in bytes of the value to be converted
|
||||
/// \return the preferred size of the INT_ZEXT output
|
||||
int4 TypeOpFloatInt2Float::preferredZextSize(int4 inSize)
|
||||
|
||||
{
|
||||
int4 outSize;
|
||||
if (inSize < 4)
|
||||
outSize = 4;
|
||||
else if (inSize < 8)
|
||||
outSize = 8;
|
||||
else
|
||||
outSize = inSize + 1;
|
||||
return outSize;
|
||||
}
|
||||
|
||||
TypeOpFloatFloat2Float::TypeOpFloatFloat2Float(TypeFactory *t,const Translate *trans)
|
||||
: TypeOpFunc(t,CPUI_FLOAT_FLOAT2FLOAT,"FLOAT2FLOAT",TYPE_FLOAT,TYPE_FLOAT)
|
||||
{
|
||||
|
|
|
@ -695,7 +695,10 @@ public:
|
|||
class TypeOpFloatInt2Float : public TypeOpFunc {
|
||||
public:
|
||||
TypeOpFloatInt2Float(TypeFactory *t,const Translate *trans); ///< Constructor
|
||||
virtual Datatype *getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const;
|
||||
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opFloatInt2Float(op); }
|
||||
static const PcodeOp *absorbZext(const PcodeOp *op);
|
||||
static int4 preferredZextSize(int4 inSize);
|
||||
};
|
||||
|
||||
/// \brief Information about the FLOAT_FLOAT2FLOAT op-code
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
<decompilertest>
|
||||
<binaryimage arch="x86:LE:64:default:gcc">
|
||||
<!-- Tests of signed and unsigned integer to floating-point conversions -->
|
||||
<bytechunk space="ram" offset="0x100000" readonly="true">
|
||||
f30f1efa83ef10660fefc0f30f2ac7f3
|
||||
0f59058d000000c3
|
||||
</bytechunk>
|
||||
<bytechunk space="ram" offset="0x1000a4" readonly="true">
|
||||
6f1283ba
|
||||
</bytechunk>
|
||||
<bytechunk space="ram" offset="0x1000aa" readonly="true">
|
||||
f30f1efa5548
|
||||
89e548897de8488b45e84883e8104885
|
||||
c07807f2480f2ac0eb154889c248d1ea
|
||||
83e0014809c2f2480f2ac2f20f58c0f2
|
||||
0f1145f8f20f104df8f20f10051f0000
|
||||
00f20f59c1f20f1145f8f20f1045f85d
|
||||
c3
|
||||
</bytechunk>
|
||||
<bytechunk space="ram" offset="0x100110" readonly="true">
|
||||
fca9f1d24d6250bf
|
||||
</bytechunk>
|
||||
<bytechunk space="ram" offset="0x140020194" readonly="true">
|
||||
4883c1f00f57c07807f2480f
|
||||
2ac1eb154889c883e10148d1e84809c8
|
||||
f2480f2ac0f20f58c0f20f5905170000
|
||||
00c20000
|
||||
</bytechunk>
|
||||
<bytechunk space="ram" offset="0x1400201d8" readonly="true">
|
||||
fca9f1d24d6250bf
|
||||
</bytechunk>
|
||||
<symbol space="ram" offset="0x100000" name="rand_calc"/>
|
||||
<symbol space="ram" offset="0x1000aa" name="rand_ulong"/>
|
||||
<symbol space="ram" offset="0x140020194" name="ulconv_win"/>
|
||||
</binaryimage>
|
||||
<script>
|
||||
<com>option readonly on</com>
|
||||
<com>parse line extern float4 rand_calc(uint4 fval);</com>
|
||||
<com>parse line extern float8 rand_ulong(uint8 lval);</com>
|
||||
<com>lo fu rand_calc</com>
|
||||
<com>dec</com>
|
||||
<com>print C</com>
|
||||
<com>lo fu rand_ulong</com>
|
||||
<com>dec</com>
|
||||
<com>print C</com>
|
||||
<com>lo fu ulconv_win</com>
|
||||
<com>map param 0 [register,8,8] uint8 llval</com>
|
||||
<com>dec</com>
|
||||
<com>print C</com>
|
||||
<com>quit</com>
|
||||
</script>
|
||||
<stringmatch name="Floating-point convert #1" min="1" max="1">return \(float4\)\(int4\)\(fval - 0x10\) \* -0.001;</stringmatch>
|
||||
<stringmatch name="Floating-point convert #2" min="1" max="1">return \(float8\)\(lval - 0x10\) \* -0.001;</stringmatch>
|
||||
<stringmatch name="Floating-point convert #3" min="1" max="1">return \(float8\)\(llval - 0x10\) \* -0.001;</stringmatch>
|
||||
</decompilertest>
|
Loading…
Reference in New Issue
Block a user