GP-5950 Add support for multipath conditional constants

This commit is contained in:
caheckman 2025-08-25 19:09:30 +00:00
parent 13ffa3a4a8
commit e412f13b30
12 changed files with 366 additions and 94 deletions

View file

@ -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|

View file

@ -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,10 +4427,11 @@ 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);
if (opc == CPUI_RETURN){
constVn = data.newConstant(varVn->getSize(), point.value);
if (opc == CPUI_RETURN) {
// CPUI_RETURN ops can't directly take constants
// as inputs
PcodeOp *copyBeforeRet = data.newOp(1, op->getAddr());
@ -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;
}

View file

@ -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 {

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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
{

View file

@ -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:

View file

@ -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

View file

@ -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

View file

@ -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>

View file

@ -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>