GP-2286 Formal boolean Varnodes

This commit is contained in:
caheckman 2022-07-05 17:21:27 -04:00
parent a438a1e1ea
commit d8835b0ecb
9 changed files with 74 additions and 48 deletions

View file

@ -1120,7 +1120,7 @@ SymbolEntry *ActionConstantPtr::isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op
int4 ActionConstantPtr::apply(Funcdata &data) int4 ActionConstantPtr::apply(Funcdata &data)
{ {
if (!data.isTypeRecoveryOn()) return 0; if (!data.hasTypeRecoveryStarted()) return 0;
if (localcount >= 4) // At most 4 passes (once type recovery starts) if (localcount >= 4) // At most 4 passes (once type recovery starts)
return 0; return 0;
@ -1208,7 +1208,7 @@ int4 ActionDeindirect::apply(Funcdata &data)
continue; continue;
} }
} }
if (data.isTypeRecoveryOn()) { if (data.hasTypeRecoveryStarted()) {
// Check for a function pointer that has an attached prototype // Check for a function pointer that has an attached prototype
Datatype *ct = op->getIn(0)->getTypeReadFacing(op); Datatype *ct = op->getIn(0)->getTypeReadFacing(op);
if ((ct->getMetatype()==TYPE_PTR)&& if ((ct->getMetatype()==TYPE_PTR)&&
@ -1486,7 +1486,7 @@ void ActionFuncLink::funcLinkOutput(FuncCallSpecs *fc,Funcdata &data)
Datatype *outtype = outparam->getType(); Datatype *outtype = outparam->getType();
if (outtype->getMetatype() != TYPE_VOID) { if (outtype->getMetatype() != TYPE_VOID) {
int4 sz = outparam->getSize(); int4 sz = outparam->getSize();
if (sz == 1 && outtype->getMetatype() == TYPE_BOOL) if (sz == 1 && outtype->getMetatype() == TYPE_BOOL && data.isTypeRecoveryOn())
data.opMarkCalculatedBool(fc->getOp()); data.opMarkCalculatedBool(fc->getOp());
Address addr = outparam->getAddress(); Address addr = outparam->getAddress();
data.newVarnodeOut(sz,addr,fc->getOp()); data.newVarnodeOut(sz,addr,fc->getOp());
@ -4792,7 +4792,7 @@ int4 ActionInferTypes::apply(Funcdata &data)
{ {
// Make sure spacebase is accurate or bases could get typed and then ptrarithed // Make sure spacebase is accurate or bases could get typed and then ptrarithed
if (!data.isTypeRecoveryOn()) return 0; if (!data.hasTypeRecoveryStarted()) return 0;
TypeFactory *typegrp = data.getArch()->types; TypeFactory *typegrp = data.getArch()->types;
Varnode *vn; Varnode *vn;
VarnodeLocSet::const_iterator iter; VarnodeLocSet::const_iterator iter;

View file

@ -65,9 +65,14 @@ public:
}; };
/// \brief Allow type recovery to start happening /// \brief Allow type recovery to start happening
///
/// The presence of \b this Action causes the function to be marked that data-type analysis
/// will be performed. Then when \b this action is applied during analysis, the function is marked
/// that data-type analysis has started.
class ActionStartTypes : public Action { class ActionStartTypes : public Action {
public: public:
ActionStartTypes(const string &g) : Action(0,"starttypes",g) {} ///< Constructor ActionStartTypes(const string &g) : Action(0,"starttypes",g) {} ///< Constructor
virtual void reset(Funcdata &data) { data.setTypeRecovery(true); }
virtual Action *clone(const ActionGroupList &grouplist) const { virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0; if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionStartTypes(getGroup()); return new ActionStartTypes(getGroup());

View file

@ -4893,7 +4893,7 @@ void FuncCallSpecs::commitNewOutputs(Funcdata &data,Varnode *newout)
// We could conceivably truncate the output to the correct size to match the parameter // We could conceivably truncate the output to the correct size to match the parameter
activeoutput.registerTrial(param->getAddress(),param->getSize()); activeoutput.registerTrial(param->getAddress(),param->getSize());
PcodeOp *indop = newout->getDef(); PcodeOp *indop = newout->getDef();
if (newout->getSize() == 1 && param->getType()->getMetatype() == TYPE_BOOL) if (newout->getSize() == 1 && param->getType()->getMetatype() == TYPE_BOOL && data.isTypeRecoveryOn())
data.opMarkCalculatedBool(op); data.opMarkCalculatedBool(op);
if (newout->getSize() == param->getSize()) { if (newout->getSize() == param->getSize()) {
if (indop != op) { if (indop != op) {

View file

@ -81,7 +81,8 @@ void Funcdata::clear(void)
{ // Clear everything associated with decompilation (analysis) { // Clear everything associated with decompilation (analysis)
flags &= ~(highlevel_on|blocks_generated|processing_started|typerecovery_on|restart_pending); flags &= ~(highlevel_on|blocks_generated|processing_started|typerecovery_start|typerecovery_on|
double_precis_on|restart_pending);
clean_up_index = 0; clean_up_index = 0;
high_level_index = 0; high_level_index = 0;
cast_phase_index = 0; cast_phase_index = 0;
@ -174,8 +175,8 @@ void Funcdata::stopProcessing(void)
bool Funcdata::startTypeRecovery(void) bool Funcdata::startTypeRecovery(void)
{ {
if ((flags & typerecovery_on)!=0) return false; // Already started if ((flags & typerecovery_start)!=0) return false; // Already started
flags |= typerecovery_on; flags |= typerecovery_start;
return true; return true;
} }

View file

@ -58,14 +58,15 @@ class Funcdata {
blocks_unreachable = 4, ///< Set if at least one basic block is currently unreachable blocks_unreachable = 4, ///< Set if at least one basic block is currently unreachable
processing_started = 8, ///< Set if processing has started processing_started = 8, ///< Set if processing has started
processing_complete = 0x10, ///< Set if processing completed processing_complete = 0x10, ///< Set if processing completed
typerecovery_on = 0x20, ///< Set if data-type recovery is started typerecovery_on = 0x20, ///< Set if data-type analysis will be performed
no_code = 0x40, ///< Set if there is no code available for this function typerecovery_start = 0x40, ///< Set if data-type recovery is started
jumptablerecovery_on = 0x80, ///< Set if \b this Funcdata object is dedicated to jump-table recovery no_code = 0x80, ///< Set if there is no code available for this function
jumptablerecovery_dont = 0x100, ///< Don't try to recover jump-tables, always truncate jumptablerecovery_on = 0x100, ///< Set if \b this Funcdata object is dedicated to jump-table recovery
restart_pending = 0x200, ///< Analysis must be restarted (because of new override info) jumptablerecovery_dont = 0x200, ///< Don't try to recover jump-tables, always truncate
unimplemented_present = 0x400, ///< Set if function contains unimplemented instructions restart_pending = 0x400, ///< Analysis must be restarted (because of new override info)
baddata_present = 0x800, ///< Set if function flowed into bad data unimplemented_present = 0x800, ///< Set if function contains unimplemented instructions
double_precis_on = 0x1000 ///< Set if we are performing double precision recovery baddata_present = 0x1000, ///< Set if function flowed into bad data
double_precis_on = 0x2000 ///< Set if we are performing double precision recovery
}; };
uint4 flags; ///< Boolean properties associated with \b this function uint4 flags; ///< Boolean properties associated with \b this function
uint4 clean_up_index; ///< Creation index of first Varnode created after start of cleanup uint4 clean_up_index; ///< Creation index of first Varnode created after start of cleanup
@ -144,7 +145,8 @@ public:
bool isProcStarted(void) const { return ((flags&processing_started)!=0); } ///< Has processing of the function started bool isProcStarted(void) const { return ((flags&processing_started)!=0); } ///< Has processing of the function started
bool isProcComplete(void) const { return ((flags&processing_complete)!=0); } ///< Is processing of the function complete bool isProcComplete(void) const { return ((flags&processing_complete)!=0); } ///< Is processing of the function complete
bool hasUnreachableBlocks(void) const { return ((flags&blocks_unreachable)!=0); } ///< Did this function exhibit unreachable code bool hasUnreachableBlocks(void) const { return ((flags&blocks_unreachable)!=0); } ///< Did this function exhibit unreachable code
bool isTypeRecoveryOn(void) const { return ((flags&typerecovery_on)!=0); } ///< Has data-type recovery processes started bool isTypeRecoveryOn(void) const { return ((flags&typerecovery_on)!=0); } ///< Will data-type analysis be performed
bool hasTypeRecoveryStarted(void) const { return ((flags&typerecovery_start)!=0); } ///< Has data-type recovery processes started
bool hasNoCode(void) const { return ((flags & no_code)!=0); } ///< Return \b true if \b this function has no code body bool hasNoCode(void) const { return ((flags & no_code)!=0); } ///< Return \b true if \b this function has no code body
void setNoCode(bool val) { if (val) flags |= no_code; else flags &= ~no_code; } ///< Toggle whether \b this has a body void setNoCode(bool val) { if (val) flags |= no_code; else flags &= ~no_code; } ///< Toggle whether \b this has a body
void setLanedRegGenerated(void) { minLanedSize = 1000000; } ///< Mark that laned registers have been collected void setLanedRegGenerated(void) { minLanedSize = 1000000; } ///< Mark that laned registers have been collected
@ -169,6 +171,11 @@ public:
void startProcessing(void); ///< Start processing for this function void startProcessing(void); ///< Start processing for this function
void stopProcessing(void); ///< Mark that processing has completed for this function void stopProcessing(void); ///< Mark that processing has completed for this function
bool startTypeRecovery(void); ///< Mark that data-type analysis has started bool startTypeRecovery(void); ///< Mark that data-type analysis has started
/// \brief Toggle whether data-type recovery will be performed on \b this function
///
/// \param val is \b true if data-type analysis is enabled
void setTypeRecovery(bool val) { flags = val ? (flags | typerecovery_on) : (flags & ~typerecovery_on); }
void startCastPhase(void) { cast_phase_index = vbank.getCreateIndex(); } ///< Start the \b cast insertion phase void startCastPhase(void) { cast_phase_index = vbank.getCreateIndex(); } ///< Start the \b cast insertion phase
uint4 getCastPhaseIndex(void) const { return cast_phase_index; } ///< Get creation index at the start of \b cast insertion uint4 getCastPhaseIndex(void) const { return cast_phase_index; } ///< Get creation index at the start of \b cast insertion
uint4 getHighLevelIndex(void) const { return high_level_index; } ///< Get creation index at the start of HighVariable creation uint4 getHighLevelIndex(void) const { return high_level_index; } ///< Get creation index at the start of HighVariable creation

View file

@ -2641,7 +2641,6 @@ int4 RuleBooleanNegate::applyOp(PcodeOp *op,Funcdata &data)
OpCode opc; OpCode opc;
Varnode *constvn; Varnode *constvn;
Varnode *subbool; Varnode *subbool;
PcodeOp *subop;
bool negate; bool negate;
uintb val; uintb val;
@ -2656,9 +2655,7 @@ int4 RuleBooleanNegate::applyOp(PcodeOp *op,Funcdata &data)
if (val==0) if (val==0)
negate = !negate; negate = !negate;
if (!subbool->isWritten()) return 0; if (!subbool->isBooleanValue(data.isTypeRecoveryOn())) return 0;
subop = subbool->getDef();
if (!subop->isCalculatedBool()) return 0; // Subexpression must be boolean output
data.opRemoveInput(op,1); // Remove second parameter data.opRemoveInput(op,1); // Remove second parameter
data.opSetInput(op,subbool,0); // Keep original boolean parameter data.opSetInput(op,subbool,0); // Keep original boolean parameter
@ -2687,15 +2684,15 @@ void RuleBoolZext::getOpList(vector<uint4> &oplist) const
int4 RuleBoolZext::applyOp(PcodeOp *op,Funcdata &data) int4 RuleBoolZext::applyOp(PcodeOp *op,Funcdata &data)
{ {
PcodeOp *boolop1,*multop1,*actionop; Varnode *boolVn1,*boolVn2;
PcodeOp *boolop2,*zextop2,*multop2; PcodeOp *multop1,*actionop;
PcodeOp *zextop2,*multop2;
uintb coeff,val; uintb coeff,val;
OpCode opc; OpCode opc;
int4 size; int4 size;
if (!op->getIn(0)->isWritten()) return 0; boolVn1 = op->getIn(0);
boolop1 = op->getIn(0)->getDef(); if (!boolVn1->isBooleanValue(data.isTypeRecoveryOn())) return 0;
if (!boolop1->isCalculatedBool()) return 0;
multop1 = op->getOut()->loneDescend(); multop1 = op->getOut()->loneDescend();
if (multop1 == (PcodeOp *)0) return 0; if (multop1 == (PcodeOp *)0) return 0;
@ -2717,7 +2714,7 @@ int4 RuleBoolZext::applyOp(PcodeOp *op,Funcdata &data)
PcodeOp *newop = data.newOp(1,op->getAddr()); PcodeOp *newop = data.newOp(1,op->getAddr());
data.opSetOpcode(newop,CPUI_BOOL_NEGATE); // Negate the boolean data.opSetOpcode(newop,CPUI_BOOL_NEGATE); // Negate the boolean
vn = data.newUniqueOut(1,newop); vn = data.newUniqueOut(1,newop);
data.opSetInput(newop,boolop1->getOut(),0); data.opSetInput(newop,boolVn1,0);
data.opInsertBefore(newop,op); data.opInsertBefore(newop,op);
data.opSetInput(op,vn,0); data.opSetInput(op,vn,0);
data.opRemoveInput(actionop,1); // eliminate the INT_ADD operator data.opRemoveInput(actionop,1); // eliminate the INT_ADD operator
@ -2742,7 +2739,7 @@ int4 RuleBoolZext::applyOp(PcodeOp *op,Funcdata &data)
else if (val != 0) else if (val != 0)
return 0; // Not comparing with 0 or -1 return 0; // Not comparing with 0 or -1
data.opSetInput(actionop,boolop1->getOut(),0); data.opSetInput(actionop,boolVn1,0);
data.opSetInput(actionop,data.newConstant(1,val),1); data.opSetInput(actionop,data.newConstant(1,val),1);
return 1; return 1;
case CPUI_INT_AND: case CPUI_INT_AND:
@ -2771,17 +2768,16 @@ int4 RuleBoolZext::applyOp(PcodeOp *op,Funcdata &data)
zextop2 = multop2->getIn(0)->getDef(); zextop2 = multop2->getIn(0)->getDef();
if (zextop2 == (PcodeOp *)0) return 0; if (zextop2 == (PcodeOp *)0) return 0;
if (zextop2->code() != CPUI_INT_ZEXT) return 0; if (zextop2->code() != CPUI_INT_ZEXT) return 0;
boolop2 = zextop2->getIn(0)->getDef(); boolVn2 = zextop2->getIn(0);
if (boolop2 == (PcodeOp *)0) return 0; if (!boolVn2->isBooleanValue(data.isTypeRecoveryOn())) return 0;
if (!boolop2->isCalculatedBool()) return 0;
// Do the boolean calculation on unextended boolean values // Do the boolean calculation on unextended boolean values
// and then extend the result // and then extend the result
PcodeOp *newop = data.newOp(2,actionop->getAddr()); PcodeOp *newop = data.newOp(2,actionop->getAddr());
Varnode *newres = data.newUniqueOut(1,newop); Varnode *newres = data.newUniqueOut(1,newop);
data.opSetOpcode(newop,opc); data.opSetOpcode(newop,opc);
data.opSetInput(newop, boolop1->getOut(), 0); data.opSetInput(newop, boolVn1, 0);
data.opSetInput(newop, boolop2->getOut(), 1); data.opSetInput(newop, boolVn2, 1);
data.opInsertBefore(newop,actionop); data.opInsertBefore(newop,actionop);
PcodeOp *newzext = data.newOp(1,actionop->getAddr()); PcodeOp *newzext = data.newOp(1,actionop->getAddr());
@ -2811,19 +2807,17 @@ void RuleLogic2Bool::getOpList(vector<uint4> &oplist) const
int4 RuleLogic2Bool::applyOp(PcodeOp *op,Funcdata &data) int4 RuleLogic2Bool::applyOp(PcodeOp *op,Funcdata &data)
{ {
PcodeOp *boolop; Varnode *boolVn;
if (!op->getIn(0)->isWritten()) return 0; boolVn = op->getIn(0);
boolop = op->getIn(0)->getDef(); if (!boolVn->isBooleanValue(data.isTypeRecoveryOn())) return 0;
if (!boolop->isCalculatedBool()) return 0;
Varnode *in1 = op->getIn(1); Varnode *in1 = op->getIn(1);
if (!in1->isWritten()) { if (in1->isConstant()) {
if ((!in1->isConstant())||(in1->getOffset()>(uintb)1)) // If one side is a constant 0 or 1, this is boolean if (in1->getOffset()>(uintb)1) // If one side is a constant 0 or 1, this is boolean
return 0; return 0;
} }
else { else if (!in1->isBooleanValue(data.isTypeRecoveryOn())) {
boolop = op->getIn(1)->getDef(); return 0;
if (!boolop->isCalculatedBool()) return 0;
} }
switch(op->code()) { switch(op->code()) {
case CPUI_INT_AND: case CPUI_INT_AND:
@ -6292,7 +6286,7 @@ int4 RulePtrArith::applyOp(PcodeOp *op,Funcdata &data)
int4 slot; int4 slot;
const Datatype *ct = (const Datatype *)0; // Unnecessary initialization const Datatype *ct = (const Datatype *)0; // Unnecessary initialization
if (!data.isTypeRecoveryOn()) return 0; if (!data.hasTypeRecoveryStarted()) return 0;
for(slot=0;slot<op->numInput();++slot) { // Search for pointer type for(slot=0;slot<op->numInput();++slot) { // Search for pointer type
ct = op->getIn(slot)->getTypeReadFacing(op); ct = op->getIn(slot)->getTypeReadFacing(op);
@ -6330,7 +6324,7 @@ int4 RuleStructOffset0::applyOp(PcodeOp *op,Funcdata &data)
{ {
int4 movesize; // Number of bytes being moved by load or store int4 movesize; // Number of bytes being moved by load or store
if (!data.isTypeRecoveryOn()) return 0; if (!data.hasTypeRecoveryStarted()) return 0;
if (op->code()==CPUI_LOAD) { if (op->code()==CPUI_LOAD) {
movesize = op->getOut()->getSize(); movesize = op->getOut()->getSize();
} }
@ -6478,7 +6472,7 @@ int4 RulePushPtr::applyOp(PcodeOp *op,Funcdata &data)
int4 slot; int4 slot;
Varnode *vni = (Varnode *)0; Varnode *vni = (Varnode *)0;
if (!data.isTypeRecoveryOn()) return 0; if (!data.hasTypeRecoveryStarted()) return 0;
for(slot=0;slot<op->numInput();++slot) { // Search for pointer type for(slot=0;slot<op->numInput();++slot) { // Search for pointer type
vni = op->getIn(slot); vni = op->getIn(slot);
if (vni->getTypeReadFacing(op)->getMetatype() == TYPE_PTR) break; if (vni->getTypeReadFacing(op)->getMetatype() == TYPE_PTR) break;
@ -6542,7 +6536,7 @@ int4 RulePtraddUndo::applyOp(PcodeOp *op,Funcdata &data)
Varnode *basevn; Varnode *basevn;
TypePointer *tp; TypePointer *tp;
if (!data.isTypeRecoveryOn()) return 0; if (!data.hasTypeRecoveryStarted()) return 0;
int4 size = (int4)op->getIn(2)->getOffset(); // Size the PTRADD thinks we are pointing int4 size = (int4)op->getIn(2)->getOffset(); // Size the PTRADD thinks we are pointing
basevn = op->getIn(0); basevn = op->getIn(0);
tp = (TypePointer *)basevn->getTypeReadFacing(op); tp = (TypePointer *)basevn->getTypeReadFacing(op);
@ -6572,7 +6566,7 @@ void RulePtrsubUndo::getOpList(vector<uint4> &oplist) const
int4 RulePtrsubUndo::applyOp(PcodeOp *op,Funcdata &data) int4 RulePtrsubUndo::applyOp(PcodeOp *op,Funcdata &data)
{ {
if (!data.isTypeRecoveryOn()) return 0; if (!data.hasTypeRecoveryStarted()) return 0;
Varnode *basevn = op->getIn(0); Varnode *basevn = op->getIn(0);
if (basevn->getTypeReadFacing(op)->isPtrsubMatching(op->getIn(1)->getOffset())) if (basevn->getTypeReadFacing(op)->isPtrsubMatching(op->getIn(1)->getOffset()))

View file

@ -317,7 +317,7 @@ void ScopeLocal::collectNameRecs(void)
void ScopeLocal::annotateRawStackPtr(void) void ScopeLocal::annotateRawStackPtr(void)
{ {
if (!fd->isTypeRecoveryOn()) return; if (!fd->hasTypeRecoveryStarted()) return;
Varnode *spVn = fd->findSpacebaseInput(space); Varnode *spVn = fd->findSpacebaseInput(space);
if (spVn == (Varnode *)0) return; if (spVn == (Varnode *)0) return;
list<PcodeOp *>::const_iterator iter; list<PcodeOp *>::const_iterator iter;

View file

@ -819,6 +819,24 @@ Datatype *Varnode::getLocalType(bool &blockup) const
return ct; return ct;
} }
/// If \b this varnode is produced by an operation with a boolean output, or if it is
/// formally marked with a boolean data-type, return \b true. The parameter \b trustAnnotation
/// toggles whether or not the formal data-type is trusted.
/// \return \b true if \b this is a formal boolean, \b false otherwise
bool Varnode::isBooleanValue(bool useAnnotation) const
{
if (isWritten()) return def->isCalculatedBool();
if (!useAnnotation)
return false;
if ((flags & (input | typelock)) == (input | typelock)) {
if (size == 1 && type->getMetatype() == TYPE_BOOL)
return true;
}
return false;
}
/// Make a local determination if \b this and \b op2 hold the same value. We check if /// Make a local determination if \b this and \b op2 hold the same value. We check if
/// there is a common ancester for which both \b this and \b op2 are created from a direct /// there is a common ancester for which both \b this and \b op2 are created from a direct
/// sequence of COPY operations. NOTE: This is a transitive relationship /// sequence of COPY operations. NOTE: This is a transitive relationship

View file

@ -328,6 +328,7 @@ public:
void copySymbol(const Varnode *vn); ///< Copy symbol info from \b vn void copySymbol(const Varnode *vn); ///< Copy symbol info from \b vn
void copySymbolIfValid(const Varnode *vn); ///< Copy symbol info from \b vn if constant value matches void copySymbolIfValid(const Varnode *vn); ///< Copy symbol info from \b vn if constant value matches
Datatype *getLocalType(bool &blockup) const; ///< Calculate type of Varnode based on local information Datatype *getLocalType(bool &blockup) const; ///< Calculate type of Varnode based on local information
bool isBooleanValue(bool useAnnotation) const; ///< Does \b this Varnode hold a formal boolean value
bool copyShadow(const Varnode *op2) const; ///< Are \b this and \b op2 copied from the same source? bool copyShadow(const Varnode *op2) const; ///< Are \b this and \b op2 copied from the same source?
void encode(Encoder &encoder) const; ///< Encode a description of \b this to a stream void encode(Encoder &encoder) const; ///< Encode a description of \b this to a stream
static bool comparePointers(const Varnode *a,const Varnode *b) { return (*a < *b); } ///< Compare Varnodes as pointers static bool comparePointers(const Varnode *a,const Varnode *b) { return (*a < *b); } ///< Compare Varnodes as pointers