mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-10 14:11:59 +00:00
Merge remote-tracking branch 'origin/GP-4790_CopyForceForm'
This commit is contained in:
commit
bc1f6b38be
@ -21,6 +21,7 @@ src/decompile/datatests/deindirect.xml||GHIDRA||||END|
|
|||||||
src/decompile/datatests/deindirect2.xml||GHIDRA||||END|
|
src/decompile/datatests/deindirect2.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/displayformat.xml||GHIDRA||||END|
|
src/decompile/datatests/displayformat.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/divopt.xml||GHIDRA||||END|
|
src/decompile/datatests/divopt.xml||GHIDRA||||END|
|
||||||
|
src/decompile/datatests/doublemove.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/dupptr.xml||GHIDRA||||END|
|
src/decompile/datatests/dupptr.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/elseif.xml||GHIDRA||||END|
|
src/decompile/datatests/elseif.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/floatcast.xml||GHIDRA||||END|
|
src/decompile/datatests/floatcast.xml||GHIDRA||||END|
|
||||||
|
@ -5545,6 +5545,7 @@ void ActionDatabase::universalAction(Architecture *conf)
|
|||||||
actprop->addRule( new RuleDoubleLoad("doubleload") );
|
actprop->addRule( new RuleDoubleLoad("doubleload") );
|
||||||
actprop->addRule( new RuleDoubleStore("doubleprecis") );
|
actprop->addRule( new RuleDoubleStore("doubleprecis") );
|
||||||
actprop->addRule( new RuleDoubleIn("doubleprecis") );
|
actprop->addRule( new RuleDoubleIn("doubleprecis") );
|
||||||
|
actprop->addRule( new RuleDoubleOut("doubleprecis") );
|
||||||
for(iter=conf->extra_pool_rules.begin();iter!=conf->extra_pool_rules.end();++iter)
|
for(iter=conf->extra_pool_rules.begin();iter!=conf->extra_pool_rules.end();++iter)
|
||||||
actprop->addRule( *iter ); // Add CPU specific rules
|
actprop->addRule( *iter ); // Add CPU specific rules
|
||||||
conf->extra_pool_rules.clear(); // Rules are now absorbed into universal
|
conf->extra_pool_rules.clear(); // Rules are now absorbed into universal
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@ -1220,6 +1220,13 @@ int4 SplitVarnode::applyRuleIn(SplitVarnode &in,Funcdata &data)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case CPUI_COPY:
|
||||||
|
if (workop->getOut()->isAddrForce()) {
|
||||||
|
CopyForceForm copyform;
|
||||||
|
if (copyform.applyRule(in, workop, workishi, data))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1385,6 +1392,47 @@ void SplitVarnode::replaceIndirectOp(Funcdata &data,SplitVarnode &out,SplitVarno
|
|||||||
out.buildHiFromWhole(data);
|
out.buildHiFromWhole(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Rewrite the double precision version of a COPY to an address forced Varnode
|
||||||
|
///
|
||||||
|
/// This assumes that we have checked that the transformation is possible. The logical input must already
|
||||||
|
/// exist, and after this method is called, the logical output will also exist. The original COPY pieces
|
||||||
|
/// are explicitly destroyed.
|
||||||
|
/// \param data is the function owning the COPYs
|
||||||
|
/// \param addr is the storage address being COPYed
|
||||||
|
/// \param in is the input to the COPYs
|
||||||
|
/// \param copylo is the original least significant COPY
|
||||||
|
/// \param copyhi is the original most significant COPY
|
||||||
|
void SplitVarnode::replaceCopyForce(Funcdata &data,const Address &addr,SplitVarnode &in,PcodeOp *copylo,PcodeOp *copyhi)
|
||||||
|
|
||||||
|
{
|
||||||
|
Varnode *inVn = in.getWhole();
|
||||||
|
bool returnForm = copyhi->stopsCopyPropagation();
|
||||||
|
if (returnForm && inVn->getAddr() != addr) {
|
||||||
|
// Placeholder for global propagation past a RETURN needs an additional COPY
|
||||||
|
PcodeOp *otherPoint1 = copyhi->getIn(0)->getDef();
|
||||||
|
PcodeOp *otherPoint2 = copylo->getIn(0)->getDef();
|
||||||
|
// We know these are COPYs in the same basic block. Compute the later one.
|
||||||
|
if (otherPoint1->getSeqNum().getOrder() < otherPoint2->getSeqNum().getOrder())
|
||||||
|
otherPoint1 = otherPoint2;
|
||||||
|
PcodeOp *otherCopy = data.newOp(1, otherPoint1->getAddr());
|
||||||
|
data.opSetOpcode(otherCopy, CPUI_COPY);
|
||||||
|
Varnode *vn = data.newVarnodeOut(in.getSize(), addr, otherCopy);
|
||||||
|
data.opSetInput(otherCopy,inVn,0);
|
||||||
|
data.opInsertBefore(otherCopy, otherPoint1);
|
||||||
|
inVn = vn;
|
||||||
|
}
|
||||||
|
PcodeOp *wholeCopy = data.newOp(1, copyhi->getAddr());
|
||||||
|
data.opSetOpcode(wholeCopy, CPUI_COPY);
|
||||||
|
Varnode *outVn = data.newVarnodeOut(in.getSize(), addr, wholeCopy);
|
||||||
|
outVn->setAddrForce();
|
||||||
|
if (returnForm)
|
||||||
|
wholeCopy->setStopCopyPropagation();
|
||||||
|
data.opSetInput(wholeCopy,inVn,0);
|
||||||
|
data.opInsertBefore(wholeCopy, copyhi);
|
||||||
|
data.opDestroy(copyhi); // Destroy the original COPYs. Outputs have no descendants.
|
||||||
|
data.opDestroy(copylo);
|
||||||
|
}
|
||||||
|
|
||||||
bool AddForm::checkForCarry(PcodeOp *op)
|
bool AddForm::checkForCarry(PcodeOp *op)
|
||||||
|
|
||||||
{ // If -op- matches a CARRY construction based on lo1 (i.e. CARRY(x,lo1) )
|
{ // If -op- matches a CARRY construction based on lo1 (i.e. CARRY(x,lo1) )
|
||||||
@ -3151,6 +3199,73 @@ bool IndirectForm::applyRule(SplitVarnode &i,PcodeOp *ind,bool workishi,Funcdata
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Starting with the input pieces, identify the matching COPYs and verify that they act as a single
|
||||||
|
/// address forced COPY with no descendants.
|
||||||
|
/// \param h is the most significant input piece
|
||||||
|
/// \param l is the least significant input piece
|
||||||
|
/// \param w is the preexisting logical whole
|
||||||
|
/// \param cpy is the COPY of the most significant piece
|
||||||
|
bool CopyForceForm::verify(Varnode *h,Varnode *l,Varnode *w,PcodeOp *cpy)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (w == (Varnode *)0)
|
||||||
|
return false;
|
||||||
|
copyhi = cpy;
|
||||||
|
if (copyhi->getIn(0) != h) return false;
|
||||||
|
reshi = copyhi->getOut();
|
||||||
|
if (!reshi->isAddrForce() || !reshi->hasNoDescend())
|
||||||
|
return false;
|
||||||
|
list<PcodeOp *>::const_iterator iter,enditer;
|
||||||
|
iter = l->beginDescend();
|
||||||
|
enditer = l->endDescend();
|
||||||
|
while(iter != enditer) {
|
||||||
|
copylo = *iter;
|
||||||
|
++iter;
|
||||||
|
if (copylo->code() != CPUI_COPY || copylo->getParent() != copyhi->getParent())
|
||||||
|
continue;
|
||||||
|
reslo = copylo->getOut();
|
||||||
|
if (!reslo->isAddrForce() || !reslo->hasNoDescend())
|
||||||
|
continue;
|
||||||
|
if (!SplitVarnode::isAddrTiedContiguous(reslo, reshi, addrOut)) // Output MUST be contiguous addresses
|
||||||
|
continue;
|
||||||
|
if (copyhi->stopsCopyPropagation()) { // Special form has additional requirements
|
||||||
|
if (h->loneDescend() == (PcodeOp *)0)
|
||||||
|
continue;
|
||||||
|
if (l->loneDescend() == (PcodeOp *)0)
|
||||||
|
continue;
|
||||||
|
if (w->getAddr() != addrOut) { // Input whole MUST also be the same address
|
||||||
|
// Unless there are addition COPYs from the same basic block
|
||||||
|
if (!h->isWritten() || !l->isWritten())
|
||||||
|
continue;
|
||||||
|
PcodeOp *otherLo = l->getDef();
|
||||||
|
PcodeOp *otherHi = h->getDef();
|
||||||
|
if (otherLo->code() != CPUI_COPY || otherHi->code() != CPUI_COPY)
|
||||||
|
continue;
|
||||||
|
if (otherLo->getParent() != otherHi->getParent())
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \param i is the putative input to the COPYs
|
||||||
|
/// \param cpy is a putative COPY
|
||||||
|
/// \param workishi is \b true if the COPY is of the most significant piece
|
||||||
|
/// \param data is the function
|
||||||
|
bool CopyForceForm::applyRule(SplitVarnode &i,PcodeOp *cpy,bool workishi,Funcdata &data)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (!workishi) return false;
|
||||||
|
if (!i.hasBothPieces()) return false;
|
||||||
|
in = i;
|
||||||
|
if (!verify(in.getHi(),in.getLo(),in.getWhole(),cpy))
|
||||||
|
return false;
|
||||||
|
SplitVarnode::replaceCopyForce(data, addrOut, in, copylo, copyhi);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void RuleDoubleIn::reset(Funcdata &data)
|
void RuleDoubleIn::reset(Funcdata &data)
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -3168,10 +3283,10 @@ void RuleDoubleIn::getOpList(vector<uint4> &oplist) const
|
|||||||
/// If the given Varnode looks like the most significant piece, there is another SUBPIECE that looks
|
/// If the given Varnode looks like the most significant piece, there is another SUBPIECE that looks
|
||||||
/// like the least significant piece, and the whole is from an operation that produces a logical whole,
|
/// like the least significant piece, and the whole is from an operation that produces a logical whole,
|
||||||
/// then mark the Varnode (and its companion) as double precision pieces and return 1.
|
/// then mark the Varnode (and its companion) as double precision pieces and return 1.
|
||||||
/// \param data is the function owning the Varnode
|
|
||||||
/// \param vn is the given Varnode
|
/// \param vn is the given Varnode
|
||||||
/// \param subpieceOp is the SUBPIECE PcodeOp producing the Varnode
|
/// \param subpieceOp is the SUBPIECE PcodeOp producing the Varnode
|
||||||
int4 RuleDoubleIn::attemptMarking(Funcdata &data,Varnode *vn,PcodeOp *subpieceOp)
|
/// \return 1 if the pieces are marked, 0 otherwise
|
||||||
|
int4 RuleDoubleIn::attemptMarking(Varnode *vn,PcodeOp *subpieceOp)
|
||||||
|
|
||||||
{
|
{
|
||||||
Varnode *whole = subpieceOp->getIn(0);
|
Varnode *whole = subpieceOp->getIn(0);
|
||||||
@ -3190,36 +3305,10 @@ int4 RuleDoubleIn::attemptMarking(Funcdata &data,Varnode *vn,PcodeOp *subpieceOp
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Categorize opcodes as "producing a logical whole"
|
// Categorize opcodes as "producing a logical whole"
|
||||||
switch(whole->getDef()->code()) {
|
// Its hard to tell if a logical op is really being used to act on the "logical whole"
|
||||||
case CPUI_INT_ADD:
|
TypeOp *typeop = whole->getDef()->getOpcode();
|
||||||
// Its hard to tell if the bit operators are really being used to act on the "logical whole"
|
if (!typeop->isArithmeticOp() && !typeop->isFloatingPointOp())
|
||||||
// case CPUI_INT_AND:
|
return 0;
|
||||||
// case CPUI_INT_OR:
|
|
||||||
// case CPUI_INT_XOR:
|
|
||||||
// case CPUI_INT_NEGATE:
|
|
||||||
case CPUI_INT_MULT:
|
|
||||||
case CPUI_INT_DIV:
|
|
||||||
case CPUI_INT_SDIV:
|
|
||||||
case CPUI_INT_REM:
|
|
||||||
case CPUI_INT_SREM:
|
|
||||||
case CPUI_INT_2COMP:
|
|
||||||
case CPUI_FLOAT_ADD:
|
|
||||||
case CPUI_FLOAT_DIV:
|
|
||||||
case CPUI_FLOAT_MULT:
|
|
||||||
case CPUI_FLOAT_SUB:
|
|
||||||
case CPUI_FLOAT_NEG:
|
|
||||||
case CPUI_FLOAT_ABS:
|
|
||||||
case CPUI_FLOAT_SQRT:
|
|
||||||
case CPUI_FLOAT_INT2FLOAT:
|
|
||||||
case CPUI_FLOAT_FLOAT2FLOAT:
|
|
||||||
case CPUI_FLOAT_TRUNC:
|
|
||||||
case CPUI_FLOAT_CEIL:
|
|
||||||
case CPUI_FLOAT_FLOOR:
|
|
||||||
case CPUI_FLOAT_ROUND:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Varnode *vnLo = (Varnode *)0;
|
Varnode *vnLo = (Varnode *)0;
|
||||||
list<PcodeOp *>::const_iterator iter;
|
list<PcodeOp *>::const_iterator iter;
|
||||||
@ -3240,11 +3329,11 @@ int4 RuleDoubleIn::attemptMarking(Funcdata &data,Varnode *vn,PcodeOp *subpieceOp
|
|||||||
|
|
||||||
int4 RuleDoubleIn::applyOp(PcodeOp *op,Funcdata &data)
|
int4 RuleDoubleIn::applyOp(PcodeOp *op,Funcdata &data)
|
||||||
|
|
||||||
{ // Try to push double precision object "down" one level from input
|
{
|
||||||
Varnode *outvn = op->getOut();
|
Varnode *outvn = op->getOut();
|
||||||
if (!outvn->isPrecisLo()) {
|
if (!outvn->isPrecisLo()) {
|
||||||
if (outvn->isPrecisHi()) return 0;
|
if (outvn->isPrecisHi()) return 0;
|
||||||
return attemptMarking(data, outvn, op);
|
return attemptMarking(outvn, op);
|
||||||
}
|
}
|
||||||
if (data.hasUnreachableBlocks()) return 0;
|
if (data.hasUnreachableBlocks()) return 0;
|
||||||
|
|
||||||
@ -3260,6 +3349,82 @@ int4 RuleDoubleIn::applyOp(PcodeOp *op,Funcdata &data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RuleDoubleOut::getOpList(vector<uint4> &oplist) const
|
||||||
|
|
||||||
|
{
|
||||||
|
oplist.push_back(CPUI_PIECE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Determine if the given inputs to a PIECE should marked as double precision pieces
|
||||||
|
///
|
||||||
|
/// If the concatenation of the pieces is used as a logical whole by other ops, the two pieces
|
||||||
|
/// are marked and 1 is returned.
|
||||||
|
/// \param vnhi is the most significant input to the PIECE
|
||||||
|
/// \param vnlo is the least significant input
|
||||||
|
/// \param pieceOp is the op reading the pieces
|
||||||
|
/// \return 1 if the pieces are marked, 0 otherwise
|
||||||
|
int4 RuleDoubleOut::attemptMarking(Varnode *vnhi,Varnode *vnlo,PcodeOp *pieceOp)
|
||||||
|
|
||||||
|
{
|
||||||
|
Varnode *whole = pieceOp->getOut();
|
||||||
|
if (whole->isTypeLock()) {
|
||||||
|
if (!whole->getType()->isPrimitiveWhole())
|
||||||
|
return 0; // Don't mark for double precision if not a primitive type
|
||||||
|
}
|
||||||
|
if (vnhi->getSize() != vnlo->getSize())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
SymbolEntry *entryhi = vnhi->getSymbolEntry();
|
||||||
|
SymbolEntry *entrylo = vnlo->getSymbolEntry();
|
||||||
|
if (entryhi != (SymbolEntry *)0 || entrylo != (SymbolEntry *)0) {
|
||||||
|
if (entryhi == (SymbolEntry *)0 || entrylo == (SymbolEntry *)0)
|
||||||
|
return 0; // One has a symbol, one doesn't
|
||||||
|
if (entryhi->getSymbol() != entrylo->getSymbol())
|
||||||
|
return 0; // Not from the same symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isWhole = false;
|
||||||
|
list<PcodeOp *>::const_iterator iter;
|
||||||
|
for(iter=whole->beginDescend();iter!=whole->endDescend();++iter) {
|
||||||
|
TypeOp *typeop = (*iter)->getOpcode();
|
||||||
|
// Categorize op as "reading a logical whole"
|
||||||
|
if (typeop->isArithmeticOp() || typeop->isFloatingPointOp()) {
|
||||||
|
isWhole = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isWhole)
|
||||||
|
return 0;
|
||||||
|
vnhi->setPrecisHi();
|
||||||
|
vnlo->setPrecisLo();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int4 RuleDoubleOut::applyOp(PcodeOp *op,Funcdata &data)
|
||||||
|
|
||||||
|
{
|
||||||
|
Varnode *vnhi= op->getIn(0);
|
||||||
|
Varnode *vnlo = op->getIn(1);
|
||||||
|
|
||||||
|
// Currently this only implements collapsing input varnodes read by CPUI_PIECE
|
||||||
|
// So we put the test for this particular case early
|
||||||
|
if (!vnhi->isInput() || !vnlo->isInput())
|
||||||
|
return 0;
|
||||||
|
if (!vnhi->isPersist() || !vnlo->isPersist())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!vnhi->isPrecisHi() || !vnlo->isPrecisLo()) {
|
||||||
|
return attemptMarking(vnhi,vnlo,op);
|
||||||
|
}
|
||||||
|
if (data.hasUnreachableBlocks()) return 0;
|
||||||
|
|
||||||
|
Address addr;
|
||||||
|
if (!SplitVarnode::isAddrTiedContiguous(vnlo, vnhi, addr))
|
||||||
|
return 0;
|
||||||
|
data.combineInputVarnodes(vnhi,vnlo);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Scan for conflicts between two LOADs or STOREs that would prevent them from being combined
|
/// \brief Scan for conflicts between two LOADs or STOREs that would prevent them from being combined
|
||||||
///
|
///
|
||||||
/// The PcodeOps must be in the same basic block. Each PcodeOp that falls in between is examined
|
/// The PcodeOps must be in the same basic block. Each PcodeOp that falls in between is examined
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@ -95,6 +95,7 @@ public:
|
|||||||
PcodeOp *existop);
|
PcodeOp *existop);
|
||||||
static bool prepareIndirectOp(SplitVarnode &in,PcodeOp *affector);
|
static bool prepareIndirectOp(SplitVarnode &in,PcodeOp *affector);
|
||||||
static void replaceIndirectOp(Funcdata &data,SplitVarnode &out,SplitVarnode &in,PcodeOp *affector);
|
static void replaceIndirectOp(Funcdata &data,SplitVarnode &out,SplitVarnode &in,PcodeOp *affector);
|
||||||
|
static void replaceCopyForce(Funcdata &data,const Address &addr,SplitVarnode &in,PcodeOp *copylo,PcodeOp *copyhi);
|
||||||
static int4 applyRuleIn(SplitVarnode &in,Funcdata &data);
|
static int4 applyRuleIn(SplitVarnode &in,Funcdata &data);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -299,14 +300,30 @@ public:
|
|||||||
bool applyRule(SplitVarnode &i,PcodeOp *ind,bool workishi,Funcdata &data);
|
bool applyRule(SplitVarnode &i,PcodeOp *ind,bool workishi,Funcdata &data);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Simply a double precision operation, starting from a marked double precision input.
|
/// \brief Collapse two COPYs into contiguous address forced Varnodes
|
||||||
|
///
|
||||||
|
/// The inputs must be pieces of a logical whole and outputs must be address forced with no descendants.
|
||||||
|
/// Take into account special form of COPYs holding global variables upto/past a RETURN.
|
||||||
|
class CopyForceForm {
|
||||||
|
SplitVarnode in; ///< Incoming pieces to COPY
|
||||||
|
Varnode *reslo; ///< Least significant result of global COPY
|
||||||
|
Varnode *reshi; ///< Most significant result of global COPY
|
||||||
|
PcodeOp *copylo; ///< Partial COPY of least significant piece
|
||||||
|
PcodeOp *copyhi; ///< Partial COPY of most significant piece
|
||||||
|
Address addrOut; ///< Storage address
|
||||||
|
public:
|
||||||
|
bool verify(Varnode *h,Varnode *l,Varnode *w,PcodeOp *cpy); ///< Make sure the COPYs have the correct form
|
||||||
|
bool applyRule(SplitVarnode &i,PcodeOp *cpy,bool workishi,Funcdata &data); /// Verify and then collapse COPYs
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Simply a double precision operation, pushing down one level, starting from a marked double precision input.
|
||||||
///
|
///
|
||||||
/// This rule starts by trying to find a pair of Varnodes that are SUBPIECE from a whole,
|
/// This rule starts by trying to find a pair of Varnodes that are SUBPIECE from a whole,
|
||||||
/// are marked as double precision, and that are then used in some double precision operation.
|
/// are marked as double precision, and that are then used in some double precision operation.
|
||||||
/// The various operation \e forms are overlayed on the data-flow until a matching one is found. The
|
/// The various operation \e forms are overlayed on the data-flow until a matching one is found. The
|
||||||
/// pieces of the double precision operation are then transformed into a single logical operation on the whole.
|
/// pieces of the double precision operation are then transformed into a single logical operation on the whole.
|
||||||
class RuleDoubleIn : public Rule {
|
class RuleDoubleIn : public Rule {
|
||||||
int4 attemptMarking(Funcdata &data,Varnode *vn,PcodeOp *subpieceOp);
|
int4 attemptMarking(Varnode *vn,PcodeOp *subpieceOp);
|
||||||
public:
|
public:
|
||||||
RuleDoubleIn(const string &g) : Rule(g, 0, "doublein") {} ///< Constructor
|
RuleDoubleIn(const string &g) : Rule(g, 0, "doublein") {} ///< Constructor
|
||||||
virtual Rule *clone(const ActionGroupList &grouplist) const {
|
virtual Rule *clone(const ActionGroupList &grouplist) const {
|
||||||
@ -318,6 +335,20 @@ public:
|
|||||||
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// \brief Simplify a double precision operation, pulling back one level, starting from inputs to a PIECE operation
|
||||||
|
class RuleDoubleOut : public Rule {
|
||||||
|
int4 attemptMarking(Varnode *vnhi,Varnode *vnlo,PcodeOp *pieceOp);
|
||||||
|
public:
|
||||||
|
RuleDoubleOut(const string &g) : Rule(g, 0, "doubleout") {} ///< Constructor
|
||||||
|
virtual Rule *clone(const ActionGroupList &grouplist) const {
|
||||||
|
if (!grouplist.contains(getGroup())) return (Rule *)0;
|
||||||
|
return new RuleDoubleOut(getGroup());
|
||||||
|
}
|
||||||
|
virtual void getOpList(vector<uint4> &oplist) const;
|
||||||
|
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Collapse contiguous loads: `x = CONCAT44(*(ptr+4),*ptr) => x = *ptr`
|
||||||
class RuleDoubleLoad : public Rule {
|
class RuleDoubleLoad : public Rule {
|
||||||
public:
|
public:
|
||||||
RuleDoubleLoad(const string &g) : Rule( g, 0, "doubleload") {}
|
RuleDoubleLoad(const string &g) : Rule( g, 0, "doubleload") {}
|
||||||
@ -330,6 +361,7 @@ public:
|
|||||||
static PcodeOp *noWriteConflict(PcodeOp *op1,PcodeOp *op2,AddrSpace *spc,vector<PcodeOp *> *indirects);
|
static PcodeOp *noWriteConflict(PcodeOp *op1,PcodeOp *op2,AddrSpace *spc,vector<PcodeOp *> *indirects);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// \brief Collapse contiguous stores: `*ptr = SUB(x,0); *(ptr + 4) = SUB(x,4) => *ptr = x`
|
||||||
class RuleDoubleStore : public Rule {
|
class RuleDoubleStore : public Rule {
|
||||||
public:
|
public:
|
||||||
RuleDoubleStore(const string &g) : Rule( g, 0, "doublestore") {}
|
RuleDoubleStore(const string &g) : Rule( g, 0, "doublestore") {}
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@ -288,6 +288,7 @@ public:
|
|||||||
Varnode *newUnique(int4 s,Datatype *ct=(Datatype *)0); ///< Create a new \e temporary Varnode
|
Varnode *newUnique(int4 s,Datatype *ct=(Datatype *)0); ///< Create a new \e temporary Varnode
|
||||||
Varnode *newCodeRef(const Address &m); ///< Create a code address \e annotation Varnode
|
Varnode *newCodeRef(const Address &m); ///< Create a code address \e annotation Varnode
|
||||||
Varnode *setInputVarnode(Varnode *vn); ///< Mark a Varnode as an input to the function
|
Varnode *setInputVarnode(Varnode *vn); ///< Mark a Varnode as an input to the function
|
||||||
|
void combineInputVarnodes(Varnode *vnHi,Varnode *vnLo); ///< Combine two contiguous input Varnodes into one
|
||||||
Varnode *newExtendedConstant(int4 s,uint8 *val,PcodeOp *op); ///< Create extended precision constant
|
Varnode *newExtendedConstant(int4 s,uint8 *val,PcodeOp *op); ///< Create extended precision constant
|
||||||
void adjustInputVarnodes(const Address &addr,int4 sz);
|
void adjustInputVarnodes(const Address &addr,int4 sz);
|
||||||
void deleteVarnode(Varnode *vn) { vbank.destroy(vn); } ///< Delete the given varnode
|
void deleteVarnode(Varnode *vn) { vbank.destroy(vn); } ///< Delete the given varnode
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@ -372,6 +372,78 @@ Varnode *Funcdata::setInputVarnode(Varnode *vn)
|
|||||||
return vn;
|
return vn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A new Varnode that covers both the original Varnodes is created and is itself marked as a function input.
|
||||||
|
/// Any CPUI_PIECE reading the original Varnodes is converted to a CPUI_COPY reading the new Varnode. If there
|
||||||
|
/// are other ops reading the original Varnodes, they are changed to read replacement Varnodes, which are
|
||||||
|
/// defined as SUBPIECEs of the new Varnode. The original Varnodes are destroyed.
|
||||||
|
/// \param vnHi is the most significant Varnode to combine
|
||||||
|
/// \param vnLo is the least significant Varnode
|
||||||
|
void Funcdata::combineInputVarnodes(Varnode *vnHi,Varnode *vnLo)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (!vnHi->isInput() || !vnLo->isInput())
|
||||||
|
throw LowlevelError("Varnodes being combined are not inputs");
|
||||||
|
bool isContiguous;
|
||||||
|
Address addr = vnLo->getAddr();
|
||||||
|
if (addr.isBigEndian()) {
|
||||||
|
addr = vnHi->getAddr();
|
||||||
|
Address otheraddr = addr + vnHi->getSize();
|
||||||
|
isContiguous = (otheraddr == vnLo->getAddr());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Address otheraddr = addr + vnLo->getSize();
|
||||||
|
isContiguous = (otheraddr == vnHi->getAddr());
|
||||||
|
}
|
||||||
|
if (!isContiguous)
|
||||||
|
throw LowlevelError("Input varnodes being combined are not contiguous");
|
||||||
|
vector<PcodeOp *> pieceList;
|
||||||
|
bool otherOps = false;
|
||||||
|
list<PcodeOp *>::const_iterator iter;
|
||||||
|
for(iter=vnHi->beginDescend();iter!=vnHi->endDescend();++iter) {
|
||||||
|
PcodeOp *op = *iter;
|
||||||
|
if (op->code() == CPUI_PIECE && op->getIn(0) == vnHi && op->getIn(1) == vnLo)
|
||||||
|
pieceList.push_back(op);
|
||||||
|
else
|
||||||
|
otherOps = true;
|
||||||
|
}
|
||||||
|
for(int4 i=0;i<pieceList.size();++i) {
|
||||||
|
opRemoveInput(pieceList[i], 1);
|
||||||
|
opUnsetInput(pieceList[i], 0);
|
||||||
|
}
|
||||||
|
PcodeOp *subHi = (PcodeOp *)0;
|
||||||
|
PcodeOp *subLo = (PcodeOp *)0;
|
||||||
|
if (otherOps) {
|
||||||
|
// If there are other PcodeOps besides PIECEs that are directly combining vnHi and vnLo
|
||||||
|
// create replacement Varnodes constructed as SUBPIECEs of the new combined Varnode
|
||||||
|
BlockBasic *bb = (BlockBasic *)bblocks.getBlock(0);
|
||||||
|
subHi = newOp(2,bb->getStart());
|
||||||
|
opSetOpcode(subHi, CPUI_SUBPIECE);
|
||||||
|
opSetInput(subHi,newConstant(4, vnLo->getSize()),1);
|
||||||
|
Varnode *newHi = newVarnodeOut(vnHi->getSize(),vnHi->getAddr(),subHi);
|
||||||
|
opInsertBegin(subHi, bb);
|
||||||
|
subLo = newOp(2,bb->getStart());
|
||||||
|
opSetOpcode(subLo, CPUI_SUBPIECE);
|
||||||
|
opSetInput(subLo,newConstant(4, 0),1);
|
||||||
|
Varnode *newLo = newVarnodeOut(vnLo->getSize(),vnLo->getAddr(),subLo);
|
||||||
|
opInsertBegin(subLo, bb);
|
||||||
|
totalReplace(vnHi, newHi);
|
||||||
|
totalReplace(vnLo, newLo);
|
||||||
|
}
|
||||||
|
int4 outSize = vnHi->getSize() + vnLo->getSize();
|
||||||
|
vbank.destroy(vnHi);
|
||||||
|
vbank.destroy(vnLo);
|
||||||
|
Varnode *inVn = newVarnode(outSize, addr);
|
||||||
|
inVn = setInputVarnode(inVn);
|
||||||
|
for(int4 i=0;i<pieceList.size();++i) {
|
||||||
|
opSetInput(pieceList[i],inVn,0);
|
||||||
|
opSetOpcode(pieceList[i], CPUI_COPY);
|
||||||
|
}
|
||||||
|
if (otherOps) {
|
||||||
|
opSetInput(subHi,inVn,0);
|
||||||
|
opSetInput(subLo,inVn,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Construct a constant Varnode up to 128 bits, using INT_ZEXT and PIECE if necessary.
|
/// Construct a constant Varnode up to 128 bits, using INT_ZEXT and PIECE if necessary.
|
||||||
/// This method is temporary until we have full extended precision constants.
|
/// This method is temporary until we have full extended precision constants.
|
||||||
/// \param s is the size of the Varnode in bytes
|
/// \param s is the size of the Varnode in bytes
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
<decompilertest>
|
||||||
|
<!--
|
||||||
|
Functions with variables that are LOADed are STOREed in two stages,
|
||||||
|
but also used as a logical whole.
|
||||||
|
-->
|
||||||
|
<binaryimage arch="MIPS:BE:32:default:default">
|
||||||
|
<bytechunk space="ram" offset="0x400000" readonly="true">
|
||||||
|
3c020042d4424318afa40000
|
||||||
|
c4414318c440431cafa60008afa7000c
|
||||||
|
03e0000846201000
|
||||||
|
</bytechunk>
|
||||||
|
<bytechunk space="ram" offset="0x410000" readonly="true">
|
||||||
|
3c020042d7a20028afa40000
|
||||||
|
c4414320c440432446201000e4414308
|
||||||
|
e440430c03e0000846201000
|
||||||
|
</bytechunk>
|
||||||
|
<bytechunk space="ram" offset="0x424320" readonly="true">
|
||||||
|
401c000000000000
|
||||||
|
</bytechunk>
|
||||||
|
<symbol space="ram" offset="0x400000" name="loaddouble"/>
|
||||||
|
<symbol space="ram" offset="0x410000" name="storedouble"/>
|
||||||
|
</binaryimage>
|
||||||
|
<script>
|
||||||
|
<com>option readonly on</com>
|
||||||
|
<com>map addr r0x424318 float8 glob1</com>
|
||||||
|
<com>map addr r0x424308 float8 glob2</com>
|
||||||
|
<com>lo fu loaddouble</com>
|
||||||
|
<com>dec</com>
|
||||||
|
<com>print C</com>
|
||||||
|
<com>print raw</com>
|
||||||
|
<com>lo fu storedouble</com>
|
||||||
|
<com>dec</com>
|
||||||
|
<com>print C</com>
|
||||||
|
<com>print raw</com>
|
||||||
|
</script>
|
||||||
|
<stringmatch name="Double precision move #1" min="1" max="1">return glob1 \+ glob1;</stringmatch>
|
||||||
|
<stringmatch name="Double precision move #2" min="1" max="1">r0x00424318:8\(i\) \+ r0x00424318:8\(i\)</stringmatch>
|
||||||
|
<stringmatch name="Double precision move #3" min="1" max="1">r0x00424318:8\(0x.*\) = r0x00424318:8\(i\)</stringmatch>
|
||||||
|
<stringmatch name="Double precision move #4" min="1" max="1">glob2 = in_stack_00000028 \+ 7\.0;</stringmatch>
|
||||||
|
<stringmatch name="Double precision move #5" min="1" max="1">r0x00424308.* = f0_1.*</stringmatch>
|
||||||
|
<stringmatch name="Double precision move #6" min="1" max="1">r0x00424308.* = r0x00424308.*</stringmatch>
|
||||||
|
</decompilertest>
|
Loading…
Reference in New Issue
Block a user