mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
GP-5950 Add support for multipath conditional constants
This commit is contained in:
parent
13ffa3a4a8
commit
e412f13b30
12 changed files with 366 additions and 94 deletions
|
@ -17,6 +17,8 @@ src/decompile/datatests/ccmp.xml||GHIDRA||||END|
|
|||
src/decompile/datatests/concat.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/concatsplit.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/condconst.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/condconst2.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/condconstsub.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/condexesub.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/condmulti.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/convert.xml||GHIDRA||||END|
|
||||
|
|
|
@ -4248,6 +4248,40 @@ void ActionConditionalConst::placeMultipleConstants(vector<PcodeOpNode> &phiNode
|
|||
}
|
||||
}
|
||||
|
||||
/// \brief Try to push the constant at the front point through to the output of the given PcodeOp
|
||||
///
|
||||
/// If successful, create a ConstPoint to search for reads of this new constant.
|
||||
/// \param points is the set of points with the current point at the front
|
||||
/// \param op is p-code op to push the constant through
|
||||
void ActionConditionalConst::pushConstant(list<ConstPoint> &points,PcodeOp *op)
|
||||
|
||||
{
|
||||
if ((op->getEvalType() & PcodeOp::special) != 0) return;
|
||||
if (op->getOpcode()->isFloatingPointOp()) return;
|
||||
Varnode *outvn = op->getOut();
|
||||
if (outvn->getSize() > sizeof(uintb)) return;
|
||||
Varnode *vn = points.front().vn;
|
||||
int4 slot = op->getSlot(vn);
|
||||
uintb in[3];
|
||||
for(int4 i=0;i<op->numInput();++i) {
|
||||
if (i == slot)
|
||||
in[i] = points.front().value;
|
||||
else {
|
||||
Varnode *inVn = op->getIn(i);
|
||||
if (inVn->getSize() > sizeof(uintb)) return;
|
||||
if (inVn->isConstant())
|
||||
in[i] = op->getIn(i)->getOffset();
|
||||
else
|
||||
return; // Not all inputs are constant
|
||||
}
|
||||
}
|
||||
bool evalError;
|
||||
uintb outval = op->executeSimple(in,evalError);
|
||||
if (evalError)
|
||||
return;
|
||||
points.emplace_back(outvn,outval,points.front().constBlock,points.front().inSlot,points.front().blockIsDom);
|
||||
}
|
||||
|
||||
/// \brief Replace MULTIEQUAL edges with constant if there is no alternate flow
|
||||
///
|
||||
/// A given Varnode is known to be constant along a set of MULTIEQUAL edges. If these edges are excised from the
|
||||
|
@ -4297,24 +4331,61 @@ void ActionConditionalConst::handlePhiNodes(Varnode *varVn,Varnode *constVn,vect
|
|||
}
|
||||
}
|
||||
|
||||
/// \brief Replace reads of a given Varnode with a constant.
|
||||
/// \brief Test if we can reach the given Varnode via a path other than through the immediate edge
|
||||
///
|
||||
/// For each read op, check that is in or dominated by a specific block we known
|
||||
/// the Varnode is constant in.
|
||||
/// \param varVn is the given Varnode
|
||||
/// \param constVn is the constant Varnode to replace with (may be null)
|
||||
/// \param constVal is the constant value being propagated
|
||||
/// \param constBlock is the block which dominates ops reading the constant value
|
||||
/// The given Varnode is an input to a MULTIEQUAL through a specific input slot. If we can reach the
|
||||
/// same Varnode backtracking through one of the other slots, return \b true. We can backtrack
|
||||
/// through MULTIEQUALs up to a given depth and possibly a final INT_ADD.
|
||||
/// \param vn is the given Varnode
|
||||
/// \param op is the MULTIEQUAL reading \b vn
|
||||
/// \param slot is the input index of \b vn
|
||||
/// \param depth is the maximum depth to backtrack
|
||||
/// \return \b true if an alternate path to the Varnode is found
|
||||
bool ActionConditionalConst::testAlternatePath(Varnode *vn,PcodeOp *op,int4 slot,int4 depth)
|
||||
|
||||
{
|
||||
for(int4 i=0;i<op->numInput();++i) {
|
||||
if (i == slot) continue;
|
||||
Varnode *inVn = op->getIn(i);
|
||||
if (inVn == vn) return true;
|
||||
if (inVn->isWritten()) {
|
||||
PcodeOp *curOp = inVn->getDef();
|
||||
OpCode opc = curOp->code();
|
||||
if (opc == CPUI_INT_ADD || opc == CPUI_PTRSUB || opc == CPUI_PTRADD) {
|
||||
if (curOp->getIn(0) == vn || curOp->getIn(1) == vn)
|
||||
return true;
|
||||
}
|
||||
else if (opc == CPUI_MULTIEQUAL) {
|
||||
if (depth == 0) continue;
|
||||
if (testAlternatePath(vn,curOp,-1,depth-1))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief At each ConstPoint, replace reads of the Varnode down the constant path with a constant Varnode
|
||||
///
|
||||
/// Process ConstPoints from the front of the list.
|
||||
/// For each read op of current point's Varnode, check if it is in the constant path.
|
||||
/// If it is, replace the read with a new constant Varnode.
|
||||
/// If not in the constant path, attempt to make the output Varnode into a new ConstPoint that may have
|
||||
/// have reads in the constant path.
|
||||
/// \param points is the list of ConstPoints
|
||||
/// \param useMultiequal is \b true if conditional constants can be applied to MULTIEQUAL ops
|
||||
/// \param data is the function being analyzed
|
||||
void ActionConditionalConst::propagateConstant(Varnode *varVn,Varnode *constVn,uintb constVal,
|
||||
FlowBlock *constBlock,bool useMultiequal,Funcdata &data)
|
||||
void ActionConditionalConst::propagateConstant(list<ConstPoint> &points,bool useMultiequal,Funcdata &data)
|
||||
|
||||
{
|
||||
vector<PcodeOpNode> phiNodeEdges;
|
||||
list<PcodeOp *>::const_iterator iter,enditer;
|
||||
iter = varVn->beginDescend();
|
||||
enditer = varVn->endDescend();
|
||||
while(!points.empty()) {
|
||||
ConstPoint &point(points.front());
|
||||
Varnode *varVn = point.vn;
|
||||
Varnode *constVn = point.constVn;
|
||||
FlowBlock *constBlock = point.constBlock;
|
||||
list<PcodeOp *>::const_iterator iter = varVn->beginDescend();
|
||||
list<PcodeOp *>::const_iterator enditer = varVn->endDescend();
|
||||
while(iter != enditer) {
|
||||
PcodeOp *op = *iter;
|
||||
while(iter != enditer && *iter == op)
|
||||
|
@ -4328,6 +4399,17 @@ void ActionConditionalConst::propagateConstant(Varnode *varVn,Varnode *constVn,u
|
|||
if (varVn->isAddrTied() && varVn->getAddr() == op->getOut()->getAddr())
|
||||
continue;
|
||||
FlowBlock *bl = op->getParent();
|
||||
if (bl == constBlock) { // The immediate edge from the conditional block, coming into a MULTIEQUAL
|
||||
if (op->getIn(point.inSlot) == varVn) {
|
||||
// Its possible the compiler still intends the constant value to be the same variable
|
||||
// Test for conditions when this is likely so we don't unnecessarily create a new variable
|
||||
if (point.value > 1) continue;
|
||||
if (op->getOut()->isAddrTied()) continue;
|
||||
if (testAlternatePath(varVn, op, point.inSlot, 2)) continue;
|
||||
phiNodeEdges.emplace_back(op,point.inSlot);
|
||||
}
|
||||
}
|
||||
else if (point.blockIsDom) {
|
||||
for(int4 slot=0;slot<op->numInput();++slot) {
|
||||
if (op->getIn(slot) == varVn) {
|
||||
if (constBlock->dominates(bl->getIn(slot))) {
|
||||
|
@ -4335,6 +4417,7 @@ void ActionConditionalConst::propagateConstant(Varnode *varVn,Varnode *constVn,u
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (opc == CPUI_COPY) { // Don't propagate into COPY unless...
|
||||
|
@ -4344,9 +4427,10 @@ void ActionConditionalConst::propagateConstant(Varnode *varVn,Varnode *constVn,u
|
|||
if (followOp->code() == CPUI_COPY) continue;
|
||||
// ...unless COPY is into something more interesting
|
||||
}
|
||||
if (!point.blockIsDom) continue;
|
||||
if (constBlock->dominates(op->getParent())) {
|
||||
if (constVn == (Varnode *)0)
|
||||
constVn = data.newConstant(varVn->getSize(), constVal);
|
||||
constVn = data.newConstant(varVn->getSize(), point.value);
|
||||
if (opc == CPUI_RETURN) {
|
||||
// CPUI_RETURN ops can't directly take constants
|
||||
// as inputs
|
||||
|
@ -4363,12 +4447,63 @@ void ActionConditionalConst::propagateConstant(Varnode *varVn,Varnode *constVn,u
|
|||
}
|
||||
count += 1; // We made a change
|
||||
}
|
||||
else {
|
||||
pushConstant(points, op);
|
||||
}
|
||||
}
|
||||
if (!phiNodeEdges.empty()) {
|
||||
if (constVn == (Varnode *)0)
|
||||
constVn = data.newConstant(varVn->getSize(), constVal);
|
||||
constVn = data.newConstant(varVn->getSize(), point.value);
|
||||
handlePhiNodes(varVn, constVn, phiNodeEdges, data);
|
||||
phiNodeEdges.clear();
|
||||
}
|
||||
points.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Find a Varnode being compared to a constant creating the given CBRANCH boolean
|
||||
///
|
||||
/// If the boolean is created by comparing a Varnode to a constant, create a ConstPoint record
|
||||
/// indicating the path down which the Varnode can be considered constant.
|
||||
/// \param points will hold any new ConstPoint
|
||||
/// \param boolVn is the given CBRANCH boolean
|
||||
/// \param bl is the block constaining the CBRANCH
|
||||
/// \param blockDom is an array of booleans indicating along which out edges a constant could be pushed
|
||||
/// \param flipEdge is \b true if the meaning of the CBRANCH has been flipped
|
||||
void ActionConditionalConst::findConstCompare(list<ConstPoint> &points,Varnode *boolVn,FlowBlock *bl,
|
||||
bool *blockDom,bool flipEdge)
|
||||
{
|
||||
if (!boolVn->isWritten()) return;
|
||||
PcodeOp *compOp = boolVn->getDef();
|
||||
OpCode opc = compOp->code();
|
||||
if (opc == CPUI_BOOL_NEGATE) {
|
||||
flipEdge = !flipEdge;
|
||||
boolVn = compOp->getIn(0);
|
||||
if (!boolVn->isWritten()) return;
|
||||
compOp = boolVn->getDef();
|
||||
opc = compOp->code();
|
||||
}
|
||||
int4 constEdge; // Out edge where value is constant
|
||||
if (opc == CPUI_INT_EQUAL)
|
||||
constEdge = 1;
|
||||
else if (opc == CPUI_INT_NOTEQUAL)
|
||||
constEdge = 0;
|
||||
else
|
||||
return;
|
||||
// Find the variable and verify that it is compared to a constant
|
||||
Varnode *varVn = compOp->getIn(0);
|
||||
Varnode *constVn = compOp->getIn(1);
|
||||
if (!constVn->isConstant()) {
|
||||
if (!varVn->isConstant())
|
||||
return;
|
||||
Varnode *tmp = constVn;
|
||||
constVn = varVn;
|
||||
varVn = tmp;
|
||||
}
|
||||
if (varVn->loneDescend() != (PcodeOp *)0) return;
|
||||
if (flipEdge)
|
||||
constEdge = 1 - constEdge;
|
||||
points.emplace_back(varVn,constVn,bl->getOut(constEdge),bl->getOutRevIndex(constEdge),blockDom[constEdge]);
|
||||
}
|
||||
|
||||
int4 ActionConditionalConst::apply(Funcdata &data)
|
||||
|
@ -4384,55 +4519,23 @@ int4 ActionConditionalConst::apply(Funcdata &data)
|
|||
useMultiequal = false; // Don't propagate into MULTIEQUAL
|
||||
}
|
||||
const BlockGraph &blockGraph(data.getBasicBlocks());
|
||||
bool blockdom[2];
|
||||
bool blockDom[2];
|
||||
list<ConstPoint> points;
|
||||
for(int4 i=0;i<blockGraph.getSize();++i) {
|
||||
FlowBlock *bl = blockGraph.getBlock(i);
|
||||
PcodeOp *cBranch = bl->lastOp();
|
||||
if (cBranch == (PcodeOp *)0 || cBranch->code() != CPUI_CBRANCH) continue;
|
||||
Varnode *boolVn = cBranch->getIn(1);
|
||||
blockdom[0] = bl->getOut(0)->restrictedByConditional(bl); // Make sure boolean constant holds down false branch
|
||||
blockdom[1] = bl->getOut(1)->restrictedByConditional(bl);
|
||||
if (!blockdom[0] && !blockdom[1]) continue;
|
||||
blockDom[0] = bl->getOut(0)->restrictedByConditional(bl); // Make sure boolean constant holds down false branch
|
||||
blockDom[1] = bl->getOut(1)->restrictedByConditional(bl);
|
||||
bool flipEdge = cBranch->isBooleanFlip();
|
||||
if (boolVn->loneDescend() == (PcodeOp *)0) { // If the boolean is read more than once
|
||||
// Search for implied constants, bool=0 down false branch, bool=1 down true branch
|
||||
if (blockdom[0])
|
||||
propagateConstant(boolVn, (Varnode *)0, flipEdge ? 1 : 0, bl->getFalseOut(), useMultiequal, data);
|
||||
if (blockdom[1])
|
||||
propagateConstant(boolVn, (Varnode *)0, flipEdge ? 0 : 1, bl->getTrueOut(), useMultiequal, data);
|
||||
points.emplace_back(boolVn, flipEdge ? 1 : 0, bl->getFalseOut(),bl->getOutRevIndex(0),blockDom[0]);
|
||||
points.emplace_back(boolVn, flipEdge ? 0 : 1, bl->getTrueOut(),bl->getOutRevIndex(1),blockDom[1]);
|
||||
}
|
||||
if (!boolVn->isWritten()) continue;
|
||||
PcodeOp *compOp = boolVn->getDef();
|
||||
OpCode opc = compOp->code();
|
||||
if (opc == CPUI_BOOL_NEGATE) {
|
||||
flipEdge = !flipEdge;
|
||||
boolVn = compOp->getIn(0);
|
||||
if (!boolVn->isWritten()) continue;
|
||||
compOp = boolVn->getDef();
|
||||
opc = compOp->code();
|
||||
}
|
||||
int4 constEdge; // Out edge where value is constant
|
||||
if (opc == CPUI_INT_EQUAL)
|
||||
constEdge = 1;
|
||||
else if (opc == CPUI_INT_NOTEQUAL)
|
||||
constEdge = 0;
|
||||
else
|
||||
continue;
|
||||
// Find the variable and verify that it is compared to a constant
|
||||
Varnode *varVn = compOp->getIn(0);
|
||||
Varnode *constVn = compOp->getIn(1);
|
||||
if (!constVn->isConstant()) {
|
||||
if (!varVn->isConstant())
|
||||
continue;
|
||||
Varnode *tmp = constVn;
|
||||
constVn = varVn;
|
||||
varVn = tmp;
|
||||
}
|
||||
if (varVn->loneDescend() != (PcodeOp *)0) continue;
|
||||
if (flipEdge)
|
||||
constEdge = 1 - constEdge;
|
||||
if (!blockdom[constEdge]) continue; // Make sure condition holds
|
||||
propagateConstant(varVn,constVn,0,bl->getOut(constEdge),useMultiequal,data);
|
||||
findConstCompare(points, boolVn, bl, blockDom, flipEdge);
|
||||
propagateConstant(points, useMultiequal, data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -567,14 +567,30 @@ public:
|
|||
|
||||
/// \brief Propagate conditional constants
|
||||
class ActionConditionalConst : public Action {
|
||||
/// \brief Description of a point in control-flow where a Varnode can propagate as a constant down a conditional branch
|
||||
struct ConstPoint {
|
||||
Varnode *vn; ///< Varnode that is constant for some reads
|
||||
Varnode *constVn; ///< Representative of the constant (may be null)
|
||||
uintb value; ///< The constant value
|
||||
FlowBlock *constBlock; ///< Block that dominates all reads where vn is constant
|
||||
int4 inSlot; ///< Input edge from condition block
|
||||
bool blockIsDom; ///< Is \b true if block is dominated by constant path
|
||||
ConstPoint(Varnode *v,Varnode *c,FlowBlock *bl,int4 slot,bool isDom) {
|
||||
vn = v; constVn = c; value = c->getOffset(); constBlock = bl; inSlot = slot; blockIsDom = isDom; } ///< Construct from constant Varnode
|
||||
ConstPoint(Varnode *v,uintb val,FlowBlock *bl,int4 slot,bool isDom) {
|
||||
vn = v; constVn = (Varnode *)0; value = val; constBlock = bl; inSlot = slot; blockIsDom = isDom; } ///< Construct from constant value
|
||||
};
|
||||
static void clearMarks(const vector<PcodeOp *> &opList);
|
||||
static void collectReachable(Varnode *vn,vector<PcodeOpNode> &phiNodeEdges,vector<PcodeOp *> &reachable);
|
||||
static bool flowToAlternatePath(PcodeOp *op);
|
||||
static bool flowTogether(const vector<PcodeOpNode> &edges,int4 i,vector<int4> &result);
|
||||
static Varnode *placeCopy(PcodeOp *op,BlockBasic *bl,Varnode *constVn,Funcdata &data);
|
||||
static void findConstCompare(list<ConstPoint> &points,Varnode *boolVn,FlowBlock *bl,bool *blockDom,bool flipEdge);
|
||||
static void pushConstant(list<ConstPoint> &points,PcodeOp *op);
|
||||
static void placeMultipleConstants(vector<PcodeOpNode> &phiNodeEdges,vector<int4> &marks,Varnode *constVn,Funcdata &data);
|
||||
void handlePhiNodes(Varnode *varVn,Varnode *constVn,vector<PcodeOpNode> &phiNodeEdges,Funcdata &data);
|
||||
void propagateConstant(Varnode *varVn,Varnode *constVn,uintb constVal,FlowBlock *constBlock,bool useMultiequal,Funcdata &data);
|
||||
bool testAlternatePath(Varnode *vn,PcodeOp *op,int4 slot,int4 depth);
|
||||
void propagateConstant(list<ConstPoint> &points,bool useMultiequal,Funcdata &data);
|
||||
public:
|
||||
ActionConditionalConst(const string &g) : Action(0,"condconst",g) {} ///< Constructor
|
||||
virtual Action *clone(const ActionGroupList &grouplist) const {
|
||||
|
|
|
@ -2169,6 +2169,7 @@ bool LessThreeWay::normalizeHi(void)
|
|||
}
|
||||
hiconstform = false;
|
||||
if (vnhil2->isConstant()) {
|
||||
if (in.getSize() > sizeof(uintb)) return false; // Must have enough precision for constant
|
||||
hiconstform = true;
|
||||
hival = vnhil2->getOffset();
|
||||
SplitVarnode::getTrueFalse(hilessbool,hiflip,hilesstrue,hilessfalse);
|
||||
|
|
|
@ -471,6 +471,32 @@ uintb PcodeOp::collapse(bool &markedInput) const {
|
|||
throw LowlevelError("Invalid constant collapse");
|
||||
}
|
||||
|
||||
/// The p-code op must be \e special, or an exception is thrown. The operation is performed
|
||||
/// and if there is no evaluation error, the result is returned and \b evalError is set to \b false.
|
||||
/// \param in is an array of input values
|
||||
/// \return the result of applying \b this operation to the input values
|
||||
uintb PcodeOp::executeSimple(uintb *in,bool &evalError) const
|
||||
|
||||
{
|
||||
uint4 evalType = getEvalType();
|
||||
uintb res;
|
||||
try {
|
||||
if (evalType == PcodeOp::unary)
|
||||
res = opcode->evaluateUnary(output->getSize(),inrefs[0]->getSize(),in[0]);
|
||||
else if (evalType == PcodeOp::binary)
|
||||
res = opcode->evaluateBinary(output->getSize(),inrefs[0]->getSize(),in[0],in[1]);
|
||||
else if (evalType == PcodeOp::ternary)
|
||||
res = opcode->evaluateTernary(output->getSize(),inrefs[0]->getSize(),in[0],in[1],in[2]);
|
||||
else
|
||||
throw LowlevelError("Cannot perform simple execution of "+(string)get_opname(code()));
|
||||
} catch(EvaluationError &err) {
|
||||
evalError = true;
|
||||
return 0;
|
||||
}
|
||||
evalError = false;
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Knowing that \b this PcodeOp has collapsed its constant inputs, one of which has
|
||||
/// symbol content, figure out if the symbol should propagate to the new given output constant.
|
||||
/// \param newConst is the given output constant
|
||||
|
|
|
@ -233,6 +233,7 @@ public:
|
|||
OpCode code(void) const { return opcode->getOpcode(); } ///< Get the opcode id (enum) for this op
|
||||
bool isCommutative(void) const { return ((flags & PcodeOp::commutative)!=0); } ///< Return \b true if inputs commute
|
||||
uintb collapse(bool &markedInput) const; ///< Calculate the constant output produced by this op
|
||||
uintb executeSimple(uintb *in,bool &evalError) const; ///< Execute \b this operation on the given input values
|
||||
void collapseConstantSymbol(Varnode *newConst) const; ///< Propagate constant symbol from inputs to given output
|
||||
PcodeOp *nextOp(void) const; ///< Return the next op in the control-flow from this or \e null
|
||||
PcodeOp *previousOp(void) const; ///< Return the previous op within this op's basic block or \e null
|
||||
|
|
|
@ -130,6 +130,19 @@ uintb OpBehavior::evaluateBinary(int4 sizeout,int4 sizein,uintb in1,uintb in2) c
|
|||
throw LowlevelError("Binary emulation unimplemented for "+name);
|
||||
}
|
||||
|
||||
/// \param sizeout is the size of the output in bytes
|
||||
/// \param sizein is the size of the inputs in bytes
|
||||
/// \param in1 is the first input value
|
||||
/// \param in2 is the second input value
|
||||
/// \param in3 is the third input value
|
||||
/// \return the output value
|
||||
uintb OpBehavior::evaluateTernary(int4 sizeout,int4 sizein,uintb in1,uintb in2,uintb in3) const
|
||||
|
||||
{
|
||||
string name(get_opname(opcode));
|
||||
throw LowlevelError("Ternary emulation unimplemented for "+name);
|
||||
}
|
||||
|
||||
/// If the output value is known, recover the input value.
|
||||
/// \param sizeout is the size of the output in bytes
|
||||
/// \param out is the output value
|
||||
|
@ -752,6 +765,20 @@ uintb OpBehaviorSubpiece::evaluateBinary(int4 sizeout,int4 sizein,uintb in1,uint
|
|||
return res;
|
||||
}
|
||||
|
||||
uintb OpBehaviorPtradd::evaluateTernary(int4 sizeout,int4 sizein,uintb in1,uintb in2,uintb in3) const
|
||||
|
||||
{
|
||||
uintb res = (in1 + in2 * in3) & calc_mask(sizeout);
|
||||
return res;
|
||||
}
|
||||
|
||||
uintb OpBehaviorPtrsub::evaluateBinary(int4 sizeout,int4 sizein,uintb in1,uintb in2) const
|
||||
|
||||
{
|
||||
uintb res = (in1 + in2) & calc_mask(sizeout);
|
||||
return res;
|
||||
}
|
||||
|
||||
uintb OpBehaviorPopcount::evaluateUnary(int4 sizeout,int4 sizein,uintb in1) const
|
||||
|
||||
{
|
||||
|
|
|
@ -67,6 +67,9 @@ public:
|
|||
/// \brief Emulate the binary op-code on input values
|
||||
virtual uintb evaluateBinary(int4 sizeout,int4 sizein,uintb in1,uintb in2) const;
|
||||
|
||||
/// \brief Emulate the ternary op-code on input values
|
||||
virtual uintb evaluateTernary(int4 sizeout,int4 sizein,uintb in1,uintb in2,uintb in3) const;
|
||||
|
||||
/// \brief Reverse the binary op-code operation, recovering an input value
|
||||
virtual uintb recoverInputBinary(int4 slot,int4 sizeout,uintb out,int4 sizein,uintb in) const;
|
||||
|
||||
|
@ -506,6 +509,20 @@ public:
|
|||
virtual uintb evaluateBinary(int4 sizeout,int4 sizein,uintb in1,uintb in2) const;
|
||||
};
|
||||
|
||||
/// CPUI_PTRADD behavior
|
||||
class OpBehaviorPtradd : public OpBehavior {
|
||||
public:
|
||||
OpBehaviorPtradd(void) : OpBehavior(CPUI_PTRADD,false) {} ///< Constructor
|
||||
virtual uintb evaluateTernary(int4 sizeout,int4 sizein,uintb in1,uintb in2,uintb in3) const;
|
||||
};
|
||||
|
||||
/// CPUI_PTRSUB behavior
|
||||
class OpBehaviorPtrsub : public OpBehavior {
|
||||
public:
|
||||
OpBehaviorPtrsub(void) : OpBehavior(CPUI_PTRSUB,false) {} ///< Constructor
|
||||
virtual uintb evaluateBinary(int4 sizeout,int4 sizein,uintb in1,uintb in2) const;
|
||||
};
|
||||
|
||||
/// CPUI_POPCOUNT behavior
|
||||
class OpBehaviorPopcount : public OpBehavior {
|
||||
public:
|
||||
|
|
|
@ -2226,7 +2226,7 @@ TypeOpPtradd::TypeOpPtradd(TypeFactory *t) : TypeOp(t,CPUI_PTRADD,"+")
|
|||
{
|
||||
opflags = PcodeOp::ternary | PcodeOp::nocollapse;
|
||||
addlflags = arithmetic_op;
|
||||
behave = new OpBehavior(CPUI_PTRADD,false); // Dummy behavior
|
||||
behave = new OpBehaviorPtradd();
|
||||
}
|
||||
|
||||
Datatype *TypeOpPtradd::getInputLocal(const PcodeOp *op,int4 slot) const
|
||||
|
@ -2296,7 +2296,7 @@ TypeOpPtrsub::TypeOpPtrsub(TypeFactory *t) : TypeOp(t,CPUI_PTRSUB,"->")
|
|||
// allow this to be commutative.
|
||||
opflags = PcodeOp::binary|PcodeOp::nocollapse;
|
||||
addlflags = arithmetic_op;
|
||||
behave = new OpBehavior(CPUI_PTRSUB,false); // Dummy behavior
|
||||
behave = new OpBehaviorPtrsub();
|
||||
}
|
||||
|
||||
Datatype *TypeOpPtrsub::getOutputLocal(const PcodeOp *op) const
|
||||
|
|
|
@ -91,6 +91,17 @@ public:
|
|||
uintb evaluateBinary(int4 sizeout,int4 sizein,uintb in1,uintb in2) const {
|
||||
return behave->evaluateBinary(sizeout,sizein,in1,in2); }
|
||||
|
||||
/// \brief Emulate the ternary op-code on an input value
|
||||
///
|
||||
/// \param sizeout is the size of the output in bytes
|
||||
/// \param sizein is the size of the inputs in bytes
|
||||
/// \param in1 is the first input value
|
||||
/// \param in2 is the second input value
|
||||
/// \param in3 is the third input value
|
||||
/// \return the output value
|
||||
uintb evaluateTernary(int4 sizeout,int4 sizein,uintb in1,uintb in2,uintb in3) const {
|
||||
return behave->evaluateTernary(sizeout,sizein,in1,in2,in3); }
|
||||
|
||||
/// \brief Reverse the binary op-code operation, recovering a constant input value
|
||||
///
|
||||
/// If the output value and one of the input values is known, recover the value
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
<decompilertest>
|
||||
<binaryimage arch="ARM:LE:32:v8:default">
|
||||
<!--
|
||||
Examples of conditional constants being immediately passed to MULTIEQUAL after the branch
|
||||
-->
|
||||
<bytechunk space="ram" offset="0x4022871a">
|
||||
00b970478160
|
||||
6120fbe7
|
||||
</bytechunk>
|
||||
<bytechunk space="ram" offset="0x40228728">
|
||||
0b4601b107330360
|
||||
7047
|
||||
</bytechunk>
|
||||
<bytechunk space="ram" offset="0x40228736">
|
||||
087a613818bf01207047
|
||||
</bytechunk>
|
||||
<symbol space="ram" offset="0x4022871a" name="zeroprop"/>
|
||||
<symbol space="ram" offset="0x40228728" name="throughadd"/>
|
||||
<symbol space="ram" offset="0x40228736" name="condmove"/>
|
||||
<symbol space="ram" offset="0x40228758" name="myfunc"/>
|
||||
</binaryimage>
|
||||
<script>
|
||||
<com>set context TMode 1 [ram,0x4022871a] [ram,0x40228800]</com>
|
||||
<com>parse line extern char zeroprop(int4 *ptrint,int4 val);</com>
|
||||
<com>parse line extern void throughadd(int4 *tadd,int4 tval);</com>
|
||||
<com>parse line extern bool condmove(int4 cval,char *cptr);</com>
|
||||
<com>lo fu zeroprop</com>
|
||||
<com>decompile</com>
|
||||
<com>print C</com>
|
||||
<com>lo fu throughadd</com>
|
||||
<com>decompile</com>
|
||||
<com>print C</com>
|
||||
<com>lo fu condmove</com>
|
||||
<com>decompile</com>
|
||||
<com>print C</com>
|
||||
</script>
|
||||
<stringmatch name="Immediate Conditional #1" min="0" max="0">\(char\)ptrint</stringmatch>
|
||||
<stringmatch name="Immediate Conditional #2" min="1" max="1">return cVar1;</stringmatch>
|
||||
<stringmatch name="Immediate Conditional #3" min="1" max="1">cVar1 = '\\0';</stringmatch>
|
||||
<stringmatch name="Immediate Conditional #4" min="1" max="1">cVar1 = 'a';</stringmatch>
|
||||
<stringmatch name="Immediate Conditional #5" min="1" max="1">\*tadd = tval;</stringmatch>
|
||||
<stringmatch name="Immediate Conditional #6" min="1" max="1">tval = tval \+ 7;</stringmatch>
|
||||
<stringmatch name="Immediate Conditional #7" min="1" max="1">return cptr\[8\] != 'a';</stringmatch>
|
||||
<stringmatch name="Immediate Conditional #8" min="0" max="0">SUB</stringmatch>
|
||||
</decompilertest>
|
|
@ -0,0 +1,23 @@
|
|||
<decompilertest>
|
||||
<binaryimage arch="AARCH64:LE:64:v8A:default">
|
||||
<!--
|
||||
Example of conditional constant operated on prior to branch
|
||||
-->
|
||||
<bytechunk space="ram" offset="0x110320" readonly="true">
|
||||
400000b40b000014c0035fd6
|
||||
</bytechunk>
|
||||
</binaryimage>
|
||||
<script>
|
||||
<com>map fun r0x110320 foo</com>
|
||||
<com>override flow r0x110324 callreturn</com>
|
||||
<com>map fun r0x110350 otherfunc</com>
|
||||
<com>parse line extern int4 foo(void *ptr);</com>
|
||||
<com>lo fu foo</com>
|
||||
<com>decompile</com>
|
||||
<com>print C</com>
|
||||
</script>
|
||||
<stringmatch name="Modified conditional constant #1" min="1" max="1">return 0;</stringmatch>
|
||||
<stringmatch name="Modified conditional constant #2" min="1" max="1">iVar1 = otherfunc\(\);</stringmatch>
|
||||
<stringmatch name="Modified conditional constant #3" min="1" max="1">return iVar1;</stringmatch>
|
||||
<stringmatch name="Modified conditional constant #4" min="0" max="0">\(int4\)ptr</stringmatch>
|
||||
</decompilertest>
|
Loading…
Add table
Add a link
Reference in a new issue