mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
GP-3941 New boolean correlation test
This commit is contained in:
parent
ad532036ab
commit
8f3328856c
2 changed files with 137 additions and 323 deletions
|
@ -17,206 +17,7 @@
|
||||||
|
|
||||||
namespace ghidra {
|
namespace ghidra {
|
||||||
|
|
||||||
ConditionMarker::ConditionMarker(void)
|
const int4 BooleanExpressionMatch::maxDepth = 1;
|
||||||
|
|
||||||
{
|
|
||||||
initop = (PcodeOp *)0;
|
|
||||||
basevn = (Varnode *)0;
|
|
||||||
boolvn = (Varnode *)0;
|
|
||||||
bool2vn = (Varnode *)0;
|
|
||||||
bool3vn = (Varnode *)0;
|
|
||||||
binaryop = (PcodeOp *)0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Any marks on Varnodes in the root expression are cleared
|
|
||||||
ConditionMarker::~ConditionMarker(void)
|
|
||||||
|
|
||||||
{
|
|
||||||
basevn->clearMark();
|
|
||||||
if (boolvn != (Varnode *)0)
|
|
||||||
boolvn->clearMark();
|
|
||||||
if (bool2vn != (Varnode *)0)
|
|
||||||
bool2vn->clearMark();
|
|
||||||
if (bool3vn != (Varnode *)0)
|
|
||||||
bool3vn->clearMark();
|
|
||||||
if (binaryop != (PcodeOp *)0) {
|
|
||||||
binaryop->getIn(0)->clearMark();
|
|
||||||
binaryop->getIn(1)->clearMark();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Starting with the CBRANCH, the key Varnodes in the expression producing
|
|
||||||
/// the boolean value are marked. BOOL_NEGATE operations are traversed, but
|
|
||||||
/// otherwise only one level of operator is walked.
|
|
||||||
/// \param op is the root CBRANCH operation
|
|
||||||
void ConditionMarker::setupInitOp(PcodeOp *op)
|
|
||||||
|
|
||||||
{
|
|
||||||
initop = op;
|
|
||||||
basevn = op->getIn(1);
|
|
||||||
Varnode *curvn = basevn;
|
|
||||||
curvn->setMark();
|
|
||||||
if (curvn->isWritten()) {
|
|
||||||
PcodeOp *tmp = curvn->getDef();
|
|
||||||
if (tmp->code() == CPUI_BOOL_NEGATE) {
|
|
||||||
boolvn = tmp->getIn(0);
|
|
||||||
curvn = boolvn;
|
|
||||||
curvn->setMark();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (curvn->isWritten()) {
|
|
||||||
PcodeOp *tmp = curvn->getDef();
|
|
||||||
if (tmp->isBoolOutput()&&(tmp->getEvalType()==PcodeOp::binary)) {
|
|
||||||
binaryop = tmp;
|
|
||||||
Varnode *binvn = binaryop->getIn(0);
|
|
||||||
if (!binvn->isConstant()) {
|
|
||||||
if (binvn->isWritten()) {
|
|
||||||
PcodeOp *negop = binvn->getDef();
|
|
||||||
if (negop->code() == CPUI_BOOL_NEGATE) {
|
|
||||||
if (!negop->getIn(0)->isConstant()) {
|
|
||||||
bool2vn = negop->getIn(0);
|
|
||||||
bool2vn->setMark();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
binvn->setMark();
|
|
||||||
}
|
|
||||||
binvn = binaryop->getIn(1);
|
|
||||||
if (!binvn->isConstant()) {
|
|
||||||
if (binvn->isWritten()) {
|
|
||||||
PcodeOp *negop = binvn->getDef();
|
|
||||||
if (negop->code() == CPUI_BOOL_NEGATE) {
|
|
||||||
if (!negop->getIn(0)->isConstant()) {
|
|
||||||
bool3vn = negop->getIn(0);
|
|
||||||
bool3vn->setMark();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
binvn->setMark();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Walk the tree rooted at the given p-code op, looking for things marked in
|
|
||||||
/// the tree rooted at \b initop. Trim everything but BOOL_NEGATE operations,
|
|
||||||
/// one MULTIEQUAL, and one binary boolean operation. If there is a Varnode
|
|
||||||
/// in common with the root expression, this is returned, and the tree traversal
|
|
||||||
/// state holds the path from the boolean value to the common Varnode.
|
|
||||||
/// \param op is the given CBRANCH op to compare
|
|
||||||
/// \return the Varnode in common with the root expression or NULL
|
|
||||||
Varnode *ConditionMarker::findMatch(PcodeOp *op)
|
|
||||||
|
|
||||||
{
|
|
||||||
PcodeOp *curop;
|
|
||||||
// FlowBlock *bl = op->getParent();
|
|
||||||
state = 0;
|
|
||||||
Varnode *curvn = op->getIn(1);
|
|
||||||
multion = false;
|
|
||||||
binon = false;
|
|
||||||
|
|
||||||
matchflip = op->isBooleanFlip();
|
|
||||||
|
|
||||||
for(;;) {
|
|
||||||
if (curvn->isMark()) return curvn;
|
|
||||||
bool popstate = true;
|
|
||||||
if (curvn->isWritten()) {
|
|
||||||
curop = curvn->getDef();
|
|
||||||
if (curop->code() == CPUI_BOOL_NEGATE) {
|
|
||||||
curvn = curop->getIn(0);
|
|
||||||
if (!binon) // Only flip if we haven't seen binop yet, as binops get compared directly
|
|
||||||
matchflip = !matchflip;
|
|
||||||
popstate = false;
|
|
||||||
}
|
|
||||||
// else if (curop->code() == CPUI_MULTIEQUAL) {
|
|
||||||
// if ((curop->getParent()==bl)&&(!multion)) {
|
|
||||||
// opstate[state] = curop;
|
|
||||||
// slotstate[state] = 0;
|
|
||||||
// flipstate[state] = matchflip;
|
|
||||||
// state += 1;
|
|
||||||
// curvn = curop->Input(0);
|
|
||||||
// multion = true;
|
|
||||||
// popstate = false;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
else if (curop->isBoolOutput()&&(curop->getEvalType()==PcodeOp::binary)) {
|
|
||||||
if (!binon) {
|
|
||||||
opstate[state] = curop;
|
|
||||||
slotstate[state] = 0;
|
|
||||||
flipstate[state] = matchflip;
|
|
||||||
state += 1;
|
|
||||||
curvn = curop->getIn(0);
|
|
||||||
binon = true;
|
|
||||||
popstate = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (popstate) {
|
|
||||||
while(state > 0) {
|
|
||||||
curop = opstate[state-1];
|
|
||||||
matchflip = flipstate[state-1];
|
|
||||||
slotstate[state-1] += 1;
|
|
||||||
if (slotstate[state-1] < curop->numInput()) {
|
|
||||||
curvn = curop->getIn(slotstate[state-1]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
state -= 1;
|
|
||||||
if (opstate[state]->code() == CPUI_MULTIEQUAL)
|
|
||||||
multion = false;
|
|
||||||
else
|
|
||||||
binon = false;
|
|
||||||
}
|
|
||||||
if (state==0) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (Varnode *)0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Do the given Varnodes hold the same value, possibly as constants
|
|
||||||
///
|
|
||||||
/// \param a is the first Varnode to compare
|
|
||||||
/// \param b is the second Varnode
|
|
||||||
/// \return \b true if the Varnodes (always) hold the same value
|
|
||||||
bool ConditionMarker::varnodeSame(Varnode *a,Varnode *b)
|
|
||||||
|
|
||||||
{
|
|
||||||
if (a == b) return true;
|
|
||||||
if (a->isConstant() && b->isConstant())
|
|
||||||
return (a->getOffset() == b->getOffset());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Do the given boolean Varnodes always hold complementary values
|
|
||||||
///
|
|
||||||
/// Test if they are constants, 1 and 0, or if one is the direct BOOL_NEGATE of the other.
|
|
||||||
/// \param a is the first Varnode to compare
|
|
||||||
/// \param b is the second Varnode to compare
|
|
||||||
/// \return \b true if the Varnodes (always) hold complementary values
|
|
||||||
bool ConditionMarker::varnodeComplement(Varnode *a,Varnode *b)
|
|
||||||
|
|
||||||
{
|
|
||||||
if (a->isConstant() && b->isConstant()) {
|
|
||||||
uintb vala = a->getOffset();
|
|
||||||
uintb valb = b->getOffset();
|
|
||||||
if ((vala==0)&&(valb==1)) return true;
|
|
||||||
if ((vala==1)&&(valb==0)) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
PcodeOp *negop;
|
|
||||||
if (a->isWritten()) {
|
|
||||||
negop = a->getDef();
|
|
||||||
if (negop->code() == CPUI_BOOL_NEGATE)
|
|
||||||
if (negop->getIn(0) == b)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (b->isWritten()) {
|
|
||||||
negop = b->getDef();
|
|
||||||
if (negop->code() == CPUI_BOOL_NEGATE)
|
|
||||||
if (negop->getIn(0) == a)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Test if two operations with same opcode produce complementary boolean values
|
/// \brief Test if two operations with same opcode produce complementary boolean values
|
||||||
///
|
///
|
||||||
|
@ -225,7 +26,7 @@ bool ConditionMarker::varnodeComplement(Varnode *a,Varnode *b)
|
||||||
/// \param bin1op is the first p-code op to compare
|
/// \param bin1op is the first p-code op to compare
|
||||||
/// \param bin2op is the second p-code op to compare
|
/// \param bin2op is the second p-code op to compare
|
||||||
/// \return \b true if the two operations always produce complementary values
|
/// \return \b true if the two operations always produce complementary values
|
||||||
bool ConditionMarker::sameOpComplement(PcodeOp *bin1op,PcodeOp *bin2op)
|
bool BooleanExpressionMatch::sameOpComplement(PcodeOp *bin1op,PcodeOp *bin2op)
|
||||||
|
|
||||||
{
|
{
|
||||||
OpCode opcode = bin1op->code();
|
OpCode opcode = bin1op->code();
|
||||||
|
@ -256,108 +57,138 @@ bool ConditionMarker::sameOpComplement(PcodeOp *bin1op,PcodeOp *bin2op)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Check if given p-code ops are complements where one is an BOOL_AND and the other is an BOOL_OR
|
/// \brief Do the given Varnodes hold the same value, possibly as constants
|
||||||
///
|
///
|
||||||
/// \param bin1op is the first PcodeOp
|
/// \param a is the first Varnode to compare
|
||||||
/// \param bin2op is the second
|
/// \param b is the second Varnode
|
||||||
/// \return \b true if the p-code ops produce complementary values
|
/// \return \b true if the Varnodes (always) hold the same value
|
||||||
bool ConditionMarker::andOrComplement(PcodeOp *bin1op,PcodeOp *bin2op)
|
bool BooleanExpressionMatch::varnodeSame(Varnode *a,Varnode *b)
|
||||||
|
|
||||||
{
|
{
|
||||||
if (bin1op->code() == CPUI_BOOL_AND) {
|
if (a == b) return true;
|
||||||
if (bin2op->code() != CPUI_BOOL_OR) return false;
|
if (a->isConstant() && b->isConstant())
|
||||||
}
|
return (a->getOffset() == b->getOffset());
|
||||||
else if (bin1op->code() == CPUI_BOOL_OR) {
|
|
||||||
if (bin2op->code() != CPUI_BOOL_AND) return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Reaching here, one is AND and one is OR
|
|
||||||
if (varnodeComplement( bin1op->getIn(0), bin2op->getIn(0))) {
|
|
||||||
if (varnodeComplement( bin1op->getIn(1), bin2op->getIn(1)))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (varnodeComplement( bin1op->getIn(0), bin2op->getIn(1))) {
|
|
||||||
if (varnodeComplement( bin1op->getIn(1), bin2op->getIn(0)))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Determine if the two boolean expressions always produce the same or complementary values
|
/// \brief Determine if two boolean Varnodes hold related values
|
||||||
///
|
///
|
||||||
/// A common Varnode in the two expressions is given. If the boolean expressions are
|
/// The values may be the \e same, or opposite of each other (\e complementary).
|
||||||
/// uncorrelated, \b false is returned, otherwise \b true is returned. If the expressions
|
/// Otherwise the values are \e uncorrelated. The trees constructing each Varnode
|
||||||
/// are correlated but always hold opposite values, the field \b matchflip is set to \b true.
|
/// are examined up to a maximum \b depth. If this is exceeded \e uncorrelated is returned.
|
||||||
/// \param vn is the common Varnode
|
/// \param vn1 is the first boolean Varnode
|
||||||
/// \return \b true if the expressions are correlated
|
/// \param vn2 is the second boolean Varnode
|
||||||
bool ConditionMarker::finalJudgement(Varnode *vn)
|
/// \param depth is the maximum depth to traverse in the evaluation
|
||||||
|
/// \return the correlation class
|
||||||
|
int4 BooleanExpressionMatch::evaluate(Varnode *vn1,Varnode *vn2,int4 depth)
|
||||||
|
|
||||||
{
|
{
|
||||||
if (initop->isBooleanFlip())
|
if (vn1 == vn2) return same;
|
||||||
matchflip = !matchflip;
|
PcodeOp *op1,*op2;
|
||||||
if ((vn == basevn)&&(!binon)) // No binary operation involved
|
OpCode opc1,opc2;
|
||||||
return true;
|
if (vn1->isWritten()) {
|
||||||
if (boolvn != (Varnode *)0)
|
op1 = vn1->getDef();
|
||||||
matchflip = !matchflip;
|
opc1 = op1->code();
|
||||||
if ((vn == boolvn)&&(!binon)) // Negations involved
|
if (opc1 == CPUI_BOOL_NEGATE) {
|
||||||
return true;
|
int res = evaluate(op1->getIn(0),vn2,depth);
|
||||||
if ((binaryop == (PcodeOp *)0)||(!binon))
|
if (res == same) // Flip same <-> complementary result
|
||||||
return false; // Conditions don't match
|
res = complementary;
|
||||||
|
else if (res == complementary)
|
||||||
// Both conditions used binary op
|
res = same;
|
||||||
PcodeOp *binary2op = (PcodeOp *)0;
|
return res;
|
||||||
for(int4 i=0;i<state;++i) { // Find the binary op
|
|
||||||
binary2op = opstate[i];
|
|
||||||
if (binary2op->isBoolOutput()) break;
|
|
||||||
}
|
}
|
||||||
// Check if the binary ops are exactly the same
|
|
||||||
if (binaryop->code() == binary2op->code()) {
|
|
||||||
if (varnodeSame(binaryop->getIn(0),binary2op->getIn(0)) &&
|
|
||||||
varnodeSame(binaryop->getIn(1),binary2op->getIn(1)))
|
|
||||||
return true;
|
|
||||||
if (sameOpComplement(binaryop,binary2op)) {
|
|
||||||
matchflip = !matchflip;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
else {
|
||||||
|
op1 = (PcodeOp *)0; // Don't give up before checking if op2 is BOOL_NEGATE
|
||||||
|
opc1 = CPUI_MAX;
|
||||||
}
|
}
|
||||||
// If not, check if the binary ops are complements of one another
|
if (vn2->isWritten()) {
|
||||||
matchflip = !matchflip;
|
op2 = vn2->getDef();
|
||||||
if (andOrComplement(binaryop,binary2op))
|
opc2 = op2->code();
|
||||||
return true;
|
if (opc2 == CPUI_BOOL_NEGATE) {
|
||||||
|
int4 res = evaluate(vn1,op2->getIn(0),depth);
|
||||||
|
if (res == same) // Flip same <-> complementary result
|
||||||
|
res = complementary;
|
||||||
|
else if (res == complementary)
|
||||||
|
res = same;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return uncorrelated;
|
||||||
|
if (op1 == (PcodeOp *)0)
|
||||||
|
return uncorrelated;
|
||||||
|
if (!op1->isBoolOutput() || !op2->isBoolOutput())
|
||||||
|
return uncorrelated;
|
||||||
|
if (depth != 0 && (opc1 == CPUI_BOOL_AND || opc1 == CPUI_BOOL_OR || opc1 == CPUI_BOOL_XOR)) {
|
||||||
|
if (opc2 == CPUI_BOOL_AND || opc2 == CPUI_BOOL_OR || opc2 == CPUI_BOOL_XOR) {
|
||||||
|
if (opc1 == opc2 || (opc1 == CPUI_BOOL_AND && opc2 == CPUI_BOOL_OR) || (opc1 == CPUI_BOOL_OR && opc2 == CPUI_BOOL_AND)) {
|
||||||
|
int4 pair1 = evaluate(op1->getIn(0),op2->getIn(0),depth-1);
|
||||||
|
int4 pair2;
|
||||||
|
if (pair1 == uncorrelated) {
|
||||||
|
pair1 = evaluate(op1->getIn(0),op2->getIn(1),depth-1); // Try other possible pairing (commutative op)
|
||||||
|
if (pair1 == uncorrelated)
|
||||||
|
return uncorrelated;
|
||||||
|
pair2 = evaluate(op1->getIn(1),op2->getIn(0),depth-1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pair2 = evaluate(op1->getIn(1),op2->getIn(1),depth-1);
|
||||||
|
}
|
||||||
|
if (pair2 == uncorrelated)
|
||||||
|
return uncorrelated;
|
||||||
|
if (opc1 == opc2) {
|
||||||
|
if (pair1 == same && pair2 == same)
|
||||||
|
return same;
|
||||||
|
else if (opc1 == CPUI_BOOL_XOR) {
|
||||||
|
if (pair1 == complementary && pair2 == complementary)
|
||||||
|
return same;
|
||||||
|
return complementary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { // Must be CPUI_BOOL_AND and CPUI_BOOL_OR
|
||||||
|
if (pair1 == complementary && pair2 == complementary)
|
||||||
|
return complementary; // De Morgan's Law
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Two boolean output ops, compare them directly
|
||||||
|
if (opc1 == opc2) {
|
||||||
|
if (varnodeSame(op1->getIn(0),op2->getIn(0)) && varnodeSame(op1->getIn(1),op2->getIn(1)))
|
||||||
|
return same;
|
||||||
|
if (sameOpComplement(op1,op2)) {
|
||||||
|
return complementary;
|
||||||
|
}
|
||||||
|
return uncorrelated;
|
||||||
|
}
|
||||||
|
// Check if the binary ops are complements of one another
|
||||||
int4 slot1 = 0;
|
int4 slot1 = 0;
|
||||||
int4 slot2 = 0;
|
int4 slot2 = 0;
|
||||||
bool reorder;
|
bool reorder;
|
||||||
if (binaryop->code() != get_booleanflip(binary2op->code(),reorder))
|
if (opc1 != get_booleanflip(opc2,reorder))
|
||||||
return false;
|
return uncorrelated;
|
||||||
if (reorder) slot2 = 1;
|
if (reorder) slot2 = 1;
|
||||||
if (!varnodeSame(binaryop->getIn(slot1),binary2op->getIn(slot2)))
|
if (!varnodeSame(op1->getIn(slot1),op2->getIn(slot2)))
|
||||||
return false;
|
return uncorrelated;
|
||||||
if (!varnodeSame(binaryop->getIn(1-slot1),binary2op->getIn(1-slot2)))
|
if (!varnodeSame(op1->getIn(1-slot1),op2->getIn(1-slot2)))
|
||||||
return false;
|
return uncorrelated;
|
||||||
return true;
|
return complementary;
|
||||||
|
}
|
||||||
|
return uncorrelated;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConditionMarker::verifyCondition(PcodeOp *op,PcodeOp *iop)
|
bool BooleanExpressionMatch::verifyCondition(PcodeOp *op, PcodeOp *iop)
|
||||||
|
|
||||||
{
|
{
|
||||||
setupInitOp(iop);
|
int4 res = evaluate(op->getIn(1), iop->getIn(1), maxDepth);
|
||||||
Varnode *matchvn = findMatch(op);
|
if (res == uncorrelated)
|
||||||
if (matchvn == (Varnode *)0) return false;
|
return false;
|
||||||
if (!finalJudgement(matchvn)) return false;
|
matchflip = (res == complementary);
|
||||||
|
if (op->isBooleanFlip())
|
||||||
// Make final determination of what MULTIEQUAL slot is used
|
matchflip = !matchflip;
|
||||||
if (!multion)
|
if (iop->isBooleanFlip())
|
||||||
multislot = -1;
|
matchflip = !matchflip;
|
||||||
else {
|
|
||||||
for(int4 i=0;i<state;++i)
|
|
||||||
if (opstate[i]->code()==CPUI_MULTIEQUAL) {
|
|
||||||
multislot = slotstate[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,7 +259,7 @@ bool ConditionalExecution::verifySameCondition(void)
|
||||||
if (init_cbranch == (PcodeOp *)0) return false;
|
if (init_cbranch == (PcodeOp *)0) return false;
|
||||||
if (init_cbranch->code() != CPUI_CBRANCH) return false;
|
if (init_cbranch->code() != CPUI_CBRANCH) return false;
|
||||||
|
|
||||||
ConditionMarker tester;
|
BooleanExpressionMatch tester;
|
||||||
if (!tester.verifyCondition(cbranch,init_cbranch))
|
if (!tester.verifyCondition(cbranch,init_cbranch))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1057,7 +888,7 @@ int4 RuleOrPredicate::applyOp(PcodeOp *op,Funcdata &data)
|
||||||
if (branch0.zeroBlock == branch1.zeroBlock) return 0; // zero sets must be along different paths
|
if (branch0.zeroBlock == branch1.zeroBlock) return 0; // zero sets must be along different paths
|
||||||
}
|
}
|
||||||
else { // Make sure cbranches have shared condition and the different zero sets have complementary paths
|
else { // Make sure cbranches have shared condition and the different zero sets have complementary paths
|
||||||
ConditionMarker condmarker;
|
BooleanExpressionMatch condmarker;
|
||||||
if (!condmarker.verifyCondition(branch0.cbranch,branch1.cbranch)) return 0;
|
if (!condmarker.verifyCondition(branch0.cbranch,branch1.cbranch)) return 0;
|
||||||
if (condmarker.getMultiSlot() != -1) return 0;
|
if (condmarker.getMultiSlot() != -1) return 0;
|
||||||
branch0.discoverPathIsTrue();
|
branch0.discoverPathIsTrue();
|
||||||
|
|
|
@ -27,41 +27,24 @@ namespace ghidra {
|
||||||
/// This class determines if two CBRANCHs share the same condition. It also determines if the conditions
|
/// This class determines if two CBRANCHs share the same condition. It also determines if the conditions
|
||||||
/// are complements of each other, and/or they are shared along only one path.
|
/// are complements of each other, and/or they are shared along only one path.
|
||||||
///
|
///
|
||||||
/// The expression computing the root boolean value for one CBRANCH is marked out
|
/// Traverse (upto a specific depth) the two boolean expressions consisting of BOOL_AND, BOOL_OR, and
|
||||||
/// by setupInitOp(). For the other CBRANCH, findMatch() tries to find common Varnode
|
/// BOOL_XOR operations. Leaf operators in the expression can be other operators with boolean output (INT_LESS,
|
||||||
/// in its boolean expression and then maps a critical path from the Varnode to the final boolean.
|
/// INT_SLESS, etc.).
|
||||||
/// Assuming the common Varnode exists, the method finalJudgement() decides if the two boolean values
|
class BooleanExpressionMatch {
|
||||||
/// are the same, uncorrelated, or complements of one another.
|
enum {
|
||||||
class ConditionMarker {
|
same = 1, ///< Pair always hold the same value
|
||||||
PcodeOp *initop; ///< The root CBRANCH operation to compare against
|
complementary = 2, ///< Pair always hold complementary values
|
||||||
Varnode *basevn; ///< The boolean Varnode on which the root CBRANCH keys
|
uncorrelated = 3 ///< Pair values are uncorrelated
|
||||||
Varnode *boolvn; ///< If \b basevn is defined by BOOL_NEGATE, this is the unnegated Varnode
|
};
|
||||||
Varnode *bool2vn; ///< If the first param to \b binaryop is defined by BOOL_NEGATE, this is the unnegated Varnode
|
static const int4 maxDepth; ///< Maximum depth to trace a boolean expression
|
||||||
Varnode *bool3vn; ///< If the second param to \b binaryop is defined by BOOL_NEGATE, this is the unnegated Varnode
|
|
||||||
PcodeOp *binaryop; ///< The binary operator producing the root boolean (if non-null)
|
|
||||||
|
|
||||||
bool matchflip; ///< True if the compared CBRANCH keys on the opposite boolean value of the root
|
bool matchflip; ///< True if the compared CBRANCH keys on the opposite boolean value of the root
|
||||||
int4 state; ///< Depth of critical path
|
static bool sameOpComplement(PcodeOp *bin1op, PcodeOp *bin2op);
|
||||||
PcodeOp *opstate[2]; ///< p-code operations along the critical path
|
|
||||||
bool flipstate[2]; ///< Boolean negation along the critical path
|
|
||||||
int4 slotstate[2]; ///< Input Varnode to follow to stay on critical path
|
|
||||||
bool multion; ///< True if MULTIEQUAL used in condition
|
|
||||||
bool binon; ///< True if a binary operator is used in condition
|
|
||||||
int4 multislot; ///< Input slot of MULTIEQUAL on critical path, -1 if no MULTIEQUAL
|
|
||||||
|
|
||||||
void setupInitOp(PcodeOp *op); ///< Map out the root boolean expression
|
|
||||||
Varnode *findMatch(PcodeOp *op); ///< Find a matching Varnode in the root expression producing the given CBRANCH boolean
|
|
||||||
bool sameOpComplement(PcodeOp *bin1op, PcodeOp *bin2op);
|
|
||||||
bool andOrComplement(PcodeOp *bin1op, PcodeOp *bin2op);
|
|
||||||
bool finalJudgement(Varnode *vn);
|
|
||||||
public:
|
|
||||||
ConditionMarker(void); ///< Constructor
|
|
||||||
~ConditionMarker(void); ///< Destructor
|
|
||||||
bool verifyCondition(PcodeOp *op, PcodeOp *iop); ///< Perform the correlation test on two CBRANCH operations
|
|
||||||
int4 getMultiSlot(void) const { return multislot; } ///< Get the MULTIEQUAL slot in the critical path
|
|
||||||
bool getFlip(void) const { return matchflip; } ///< Return \b true is the expressions are anti-correlated
|
|
||||||
static bool varnodeSame(Varnode *a,Varnode *b);
|
static bool varnodeSame(Varnode *a,Varnode *b);
|
||||||
static bool varnodeComplement(Varnode *a,Varnode *b);
|
static int4 evaluate(Varnode *vn1,Varnode *vn2,int4 depth);
|
||||||
|
public:
|
||||||
|
bool verifyCondition(PcodeOp *op, PcodeOp *iop); ///< Perform the correlation test on two CBRANCH operations
|
||||||
|
int4 getMultiSlot(void) const { return -1; } ///< Get the MULTIEQUAL slot in the critical path
|
||||||
|
bool getFlip(void) const { return matchflip; } ///< Return \b true if the expressions are anti-correlated
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief A class for simplifying a series of conditionally executed statements.
|
/// \brief A class for simplifying a series of conditionally executed statements.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue