mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-25 05:32:14 +00:00
GP-3840 Adjustment to FlowBlock::restrictedByConditional
This commit is contained in:
parent
c072972153
commit
0a23876e01
@ -12,6 +12,7 @@ src/decompile/.project||GHIDRA||||END|
|
||||
src/decompile/cpp/.gitignore||GHIDRA||||END|
|
||||
src/decompile/cpp/Doxyfile||GHIDRA|||Most of this file is autogenerated by doxygen which falls under the GPL - output from GPL products are NOT GPL! - mjbell4|END|
|
||||
src/decompile/cpp/Makefile||GHIDRA||||END|
|
||||
src/decompile/datatests/boolless.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/concat.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/condconst.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/condmulti.xml||GHIDRA||||END|
|
||||
|
@ -1026,11 +1026,6 @@ ALLEXTERNALS = NO
|
||||
|
||||
EXTERNAL_GROUPS = YES
|
||||
|
||||
# The PERL_PATH should be the absolute path and name of the perl script
|
||||
# interpreter (i.e. the result of `which perl').
|
||||
|
||||
PERL_PATH = /usr/bin/perl
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
|
@ -239,7 +239,9 @@ public:
|
||||
void decodeFlowOverride(Decoder &decoder); ///< Set flow overrides from XML
|
||||
virtual ~Architecture(void); ///< Destructor
|
||||
|
||||
virtual string getDescription(void) const { return archid; } ///< Get a string describing \b this architecture
|
||||
/// \brief Get a string describing \b this architecture
|
||||
/// \return the description
|
||||
virtual string getDescription(void) const { return archid; }
|
||||
|
||||
/// \brief Print an error message to console
|
||||
///
|
||||
|
@ -407,9 +407,15 @@ bool FlowBlock::restrictedByConditional(const FlowBlock *cond) const
|
||||
{
|
||||
if (sizeIn() == 1) return true; // Its impossible for any path to come through sibling to this
|
||||
if (getImmedDom() != cond) return false; // This is not dominated by conditional block at all
|
||||
bool seenCond = false;
|
||||
for(int4 i=0;i<sizeIn();++i) {
|
||||
const FlowBlock *inBlock = getIn(i);
|
||||
if (inBlock == cond) continue; // The unique edge from cond to this
|
||||
if (inBlock == cond) {
|
||||
if (seenCond)
|
||||
return false; // Coming in from cond block on multiple direct edges
|
||||
seenCond = true;
|
||||
continue;
|
||||
}
|
||||
while(inBlock != this) {
|
||||
if (inBlock == cond) return false; // Must have come through sibling
|
||||
inBlock = inBlock->getImmedDom();
|
||||
|
@ -34,15 +34,15 @@ class Varnode;
|
||||
/// affectsTest() can do secondary testing to determine if the intersection should prevent merging.
|
||||
class PcodeOpSet {
|
||||
friend class Cover;
|
||||
vector<PcodeOp *> opList; // Ops in this set, sorted on block index, then SeqNum::order
|
||||
vector<int4> blockStart; // Index of first op in each non-empty block
|
||||
bool is_pop; // Has the populate() method been called
|
||||
vector<PcodeOp *> opList; ///< Ops in this set, sorted on block index, then SeqNum::order
|
||||
vector<int4> blockStart; ///< Index of first op in each non-empty block
|
||||
bool is_pop; ///< Has the populate() method been called
|
||||
protected:
|
||||
void addOp(PcodeOp *op) { opList.push_back(op); } ///< Add a PcodeOp into the set
|
||||
void finalize(void); // Sort ops in the set into blocks
|
||||
void finalize(void); ///< Sort ops in the set into blocks
|
||||
public:
|
||||
PcodeOpSet(void) { is_pop = false; }
|
||||
bool isPopulated(void) const { return is_pop; } /// Return \b true if \b this set is populated
|
||||
bool isPopulated(void) const { return is_pop; } ///< Return \b true if \b this set is populated
|
||||
virtual ~PcodeOpSet(void) {}
|
||||
|
||||
/// \brief Populate the PcodeOp object in \b this set
|
||||
|
@ -709,7 +709,13 @@ public:
|
||||
|
||||
virtual void encode(Encoder &encoder) const=0; ///< Encode \b this as a \<scope> element
|
||||
virtual void decode(Decoder &decoder)=0; ///< Decode \b this Scope from a \<scope> element
|
||||
virtual void decodeWrappingAttributes(Decoder &decoder) {} ///< Restore attributes for \b this Scope from wrapping element
|
||||
|
||||
/// \brief Restore attributes for \b this from a parent element that is not a Scope
|
||||
///
|
||||
/// Attributes are read from the (already opened) element, prior to reading reading the
|
||||
/// \<scope> element specific to \b this Scope
|
||||
/// \param decoder is the stream decoder
|
||||
virtual void decodeWrappingAttributes(Decoder &decoder) {}
|
||||
virtual void printEntries(ostream &s) const=0; ///< Dump a description of all SymbolEntry objects to a stream
|
||||
|
||||
/// \brief Get the number of Symbols in the given category
|
||||
|
@ -949,8 +949,15 @@ public:
|
||||
/// \return the maximum number of passes across all output parameters in \b this model
|
||||
int4 getMaxOutputDelay(void) const { return output->getMaxDelay(); }
|
||||
|
||||
virtual bool isMerged(void) const { return false; } ///< Is \b this a merged prototype model
|
||||
virtual bool isUnknown(void) const { return false; } ///< Is \b this an unrecognized prototype model
|
||||
/// \brief Is \b this a merged prototype model
|
||||
///
|
||||
/// \return \b true if \b this is a merged form of multiple independent prototype models
|
||||
virtual bool isMerged(void) const { return false; }
|
||||
|
||||
/// \brief If \b this an unrecognized prototype model
|
||||
///
|
||||
/// \return \b true if \b this is a placeholder for an unrecognized prototype model name
|
||||
virtual bool isUnknown(void) const { return false; }
|
||||
virtual void decode(Decoder &decoder); ///< Restore \b this model from a stream
|
||||
static uint4 lookupEffect(const vector<EffectRecord> &efflist,const Address &addr,int4 size);
|
||||
static int4 lookupRecord(const vector<EffectRecord> &efflist,int4 listSize,const Address &addr,int4 size);
|
||||
|
@ -25,7 +25,8 @@ ElementId ELEM_HIGHLIST = ElementId("highlist",117);
|
||||
ElementId ELEM_JUMPTABLELIST = ElementId("jumptablelist",118);
|
||||
ElementId ELEM_VARNODES = ElementId("varnodes",119);
|
||||
|
||||
/// \param nm is the (base) name of the function
|
||||
/// \param nm is the (base) name of the function, as a formal symbol
|
||||
/// \param disp is the name used when displaying the function name in output
|
||||
/// \param scope is Symbol scope associated with the function
|
||||
/// \param addr is the entry address for the function
|
||||
/// \param sym is the symbol representing the function
|
||||
|
@ -1238,7 +1238,7 @@ void Heritage::guardOutputOverlap(PcodeOp *callOp,const Address &addr,int4 size,
|
||||
///
|
||||
/// \param fc is the call site potentially returning a value
|
||||
/// \param addr is the starting address of the range
|
||||
/// \param addr is the starting address of the range relative to the callee
|
||||
/// \param transAddr is the starting address of the range relative to the callee
|
||||
/// \param size is the size of the range in bytes
|
||||
/// \param write is the set of new written Varnodes
|
||||
/// \return \b true if the INDIRECTs were created
|
||||
|
@ -323,9 +323,19 @@ public:
|
||||
virtual bool sanityCheck(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable)=0;
|
||||
|
||||
virtual JumpModel *clone(JumpTable *jt) const=0; ///< Clone \b this model
|
||||
virtual void clear(void) {} ///< Clear any non-permanent aspects of the model
|
||||
virtual void encode(Encoder &encoder) const {} ///< Encode this model to a stream
|
||||
virtual void decode(Decoder &decoder) {} ///< Decode \b this model from a stream
|
||||
|
||||
/// \brief Clear any non-permanent aspects of the model
|
||||
virtual void clear(void) {}
|
||||
|
||||
/// \brief Encode \b this model to a stream
|
||||
///
|
||||
/// \param encoder is the stream encoder
|
||||
virtual void encode(Encoder &encoder) const {}
|
||||
|
||||
/// \brief Decode \b this model from a stream
|
||||
///
|
||||
/// \param decoder is the stream decoder
|
||||
virtual void decode(Decoder &decoder) {}
|
||||
};
|
||||
|
||||
/// \brief A trivial jump-table model, where the BRANCHIND input Varnode is the switch variable
|
||||
|
@ -49,9 +49,9 @@ class Funcdata;
|
||||
/// of the Cover of an address tied Varnode and a PcodeOp in this set, affectsTest() can do
|
||||
/// secondary testing of whether the Varnode is actually modified by the PcodeOp.
|
||||
class StackAffectingOps : public PcodeOpSet {
|
||||
Funcdata &data;
|
||||
Funcdata &data; ///< The function containing these ops
|
||||
public:
|
||||
StackAffectingOps(Funcdata &fd) : data(fd) {}
|
||||
StackAffectingOps(Funcdata &fd) : data(fd) {} ///< Constructor
|
||||
virtual void populate(void);
|
||||
virtual bool affectsTest(PcodeOp *op,Varnode *vn) const;
|
||||
};
|
||||
|
@ -964,6 +964,13 @@ uint4 OptionSplitDatatypes::getOptionBit(const string &val)
|
||||
throw LowlevelError("Unknown data-type split option: "+val);
|
||||
}
|
||||
|
||||
/// \class OptionSplitDatatypes
|
||||
/// \brief Control which data-type assignments are split into multiple COPY/LOAD/STORE operations
|
||||
///
|
||||
/// Any combination of the three options can be given:
|
||||
/// - "struct" = Divide structure data-types into separate field assignments
|
||||
/// - "array" = Divide array data-types into separate element assignments
|
||||
/// - "pointer" = Divide assignments, via LOAD/STORE, through pointers
|
||||
string OptionSplitDatatypes::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const
|
||||
|
||||
{
|
||||
@ -987,6 +994,14 @@ string OptionSplitDatatypes::apply(Architecture *glb,const string &p1,const stri
|
||||
return "Split data-type configuration set";
|
||||
}
|
||||
|
||||
/// \class OptionNanIgnore
|
||||
/// \brief Which Not a Number (NaN) operations should be ignored
|
||||
///
|
||||
/// The option controls which p-code NaN operations are replaced with a \b false constant, assuming
|
||||
/// the input is a valid floating-point value.
|
||||
/// - "none" = No operations are replaced
|
||||
/// - "compare" = Replace NaN operations associated with floating-poing comparisons
|
||||
/// - "all" = Replace all NaN operations
|
||||
string OptionNanIgnore::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const
|
||||
|
||||
{
|
||||
|
@ -328,7 +328,9 @@ public:
|
||||
/// Inform the emitter that a printing group is ending.
|
||||
/// \param id is the id associated with the group (as returned by openGroup)
|
||||
virtual void closeGroup(int4 id) {}
|
||||
virtual void clear(void) { parenlevel = 0; indentlevel=0; pendPrint=(PendPrint *)0; } ///< Reset the emitter to its initial state
|
||||
|
||||
/// \brief Reset the emitter to its initial state
|
||||
virtual void clear(void) { parenlevel = 0; indentlevel=0; pendPrint=(PendPrint *)0; }
|
||||
virtual void setOutputStream(ostream *t)=0; ///< Set the output stream for the emitter
|
||||
virtual ostream *getOutputStream(void) const=0; ///< Get the current output stream
|
||||
virtual void spaces(int4 num,int4 bump=0);
|
||||
|
@ -5313,6 +5313,7 @@ Varnode *RuleSLess2Zero::getHiBit(PcodeOp *op)
|
||||
/// - `-1 s< (V & 0xf000) => -1 s< V
|
||||
/// - `CONCAT(V,W) s< 0 => V s< 0`
|
||||
/// - `-1 s< CONCAT(V,W) => -1 s> V`
|
||||
/// - `-1 s< (bool << #8*sz-1) => !bool`
|
||||
///
|
||||
/// There is a second set of forms where one side of the comparison is
|
||||
/// built out of a high and low piece, where the high piece determines the
|
||||
@ -5409,6 +5410,19 @@ int4 RuleSLess2Zero::applyOp(PcodeOp *op,Funcdata &data)
|
||||
data.opSetInput(op, data.newConstant(avn->getSize(),calc_mask(avn->getSize())), 0);
|
||||
return 1;
|
||||
}
|
||||
else if (feedOpCode == CPUI_INT_LEFT) {
|
||||
coeff = feedOp->getIn(1);
|
||||
if (!coeff->isConstant() || coeff->getOffset() != lvn->getSize() * 8 - 1)
|
||||
return 0;
|
||||
avn = feedOp->getIn(0);
|
||||
if (!avn->isWritten() || !avn->getDef()->isBoolOutput())
|
||||
return 0;
|
||||
// We have -1 s< (bool << #8*sz-1)
|
||||
data.opSetOpcode(op, CPUI_BOOL_NEGATE);
|
||||
data.opRemoveInput(op, 1);
|
||||
data.opSetInput(op, avn, 0);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (rvn->isConstant()) {
|
||||
|
@ -188,6 +188,12 @@ AddrSpace *SleighBuilder::generatePointer(const VarnodeTpl *vntpl,VarnodeData &v
|
||||
return hand.space;
|
||||
}
|
||||
|
||||
/// \brief Add in an additional offset to the address of a dynamic Varnode
|
||||
///
|
||||
/// The Varnode is ultimately read/written via LOAD/STORE operation AND has undergone a truncation
|
||||
/// operation, so an additional offset needs to get added to the pointer referencing the Varnode.
|
||||
/// \param op is the LOAD/STORE operation being generated
|
||||
/// \param vntpl is the dynamic Varnode
|
||||
void SleighBuilder::generatePointerAdd(PcodeData *op,const VarnodeTpl *vntpl)
|
||||
|
||||
{
|
||||
|
@ -2017,7 +2017,7 @@ bool SplitDatatype::testCopyConstraints(PcodeOp *copyOp)
|
||||
|
||||
/// \brief If the given Varnode is an extended precision constant, create split constants
|
||||
///
|
||||
/// Look for ZEXT(#c) and CONCAT(#c1,#c2) forms. Try to split into single precision Varnodes.
|
||||
/// Look for ZEXT(c) and CONCAT(c1,c2) forms. Try to split into single precision Varnodes.
|
||||
/// \param vn is the given Varnode
|
||||
/// \param inVarnodes will contain the split constant Varnodes
|
||||
/// \return \b true if the Varnode is an extended precision constant and the split is successful
|
||||
@ -2138,7 +2138,7 @@ void SplitDatatype::buildInSubpieces(Varnode *rootVn,PcodeOp *followOp,vector<Va
|
||||
/// Extract different pieces from the given root based on the offsets and
|
||||
/// output data-types in \b dataTypePieces.
|
||||
/// \param rootVn is the given root Varnode
|
||||
/// \param inVarnodes is the container for the new Varnodes
|
||||
/// \param outVarnodes is the container for the new Varnodes
|
||||
void SplitDatatype::buildOutVarnodes(Varnode *rootVn,vector<Varnode *> &outVarnodes)
|
||||
|
||||
{
|
||||
|
@ -213,10 +213,30 @@ public:
|
||||
virtual Datatype *getSubType(int8 off,int8 *newoff) const; ///< Recover component data-type one-level down
|
||||
virtual Datatype *nearestArrayedComponentForward(int8 off,int8 *newoff,int8 *elSize) const;
|
||||
virtual Datatype *nearestArrayedComponentBackward(int8 off,int8 *newoff,int8 *elSize) const;
|
||||
virtual int4 getHoleSize(int4 off) const { return 0; } ///< Get number of bytes at the given offset that are padding
|
||||
virtual int4 numDepend(void) const { return 0; } ///< Return number of component sub-types
|
||||
virtual Datatype *getDepend(int4 index) const { return (Datatype *)0; } ///< Return the i-th component sub-type
|
||||
virtual void printNameBase(ostream &s) const { if (!name.empty()) s<<name[0]; } ///< Print name as short prefix
|
||||
|
||||
/// \brief Get number of bytes at the given offset that are padding
|
||||
///
|
||||
/// For the given offset into \b this data-type, determine if the byte at that offset is considered
|
||||
/// padding, and if so, return the number of bytes in the padding. Otherwise, return 0.
|
||||
/// \return the number of bytes of padding or 0
|
||||
virtual int4 getHoleSize(int4 off) const { return 0; }
|
||||
|
||||
/// \brief Get the number of component sub-types making up \b this data-type
|
||||
///
|
||||
/// \return the number of components
|
||||
virtual int4 numDepend(void) const { return 0; }
|
||||
|
||||
/// \brief Get a specific component sub-type by index
|
||||
///
|
||||
/// \param index is the index specifying which sub-type to return
|
||||
/// \return the i-th component sub-type
|
||||
virtual Datatype *getDepend(int4 index) const { return (Datatype *)0; }
|
||||
|
||||
/// \brief Print (part of) the name of \b this data-type as short prefix for a label
|
||||
///
|
||||
/// This is used for building variable names to give some indication of the variable's underlying data-type
|
||||
/// \param s is the stream write the name prefix to
|
||||
virtual void printNameBase(ostream &s) const { if (!name.empty()) s<<name[0]; }
|
||||
virtual int4 compare(const Datatype &op,int4 level) const; ///< Order types for propagation
|
||||
virtual int4 compareDependency(const Datatype &op) const; ///< Compare for storage in tree structure
|
||||
virtual void encode(Encoder &encoder) const; ///< Encode the data-type to a stream
|
||||
|
@ -53,8 +53,16 @@ protected:
|
||||
uint4 addlflags; ///< Additional properties
|
||||
string name; ///< Symbol denoting this operation
|
||||
OpBehavior *behave; ///< Object for emulating the behavior of the op-code
|
||||
virtual void setMetatypeIn(type_metatype val) {} ///< Set the data-type associated with inputs to this opcode
|
||||
virtual void setMetatypeOut(type_metatype val) {} ///< Set the data-type associated with outputs of this opcode
|
||||
|
||||
/// \brief Set the data-type (as a meta-type) associated with inputs to this opcode
|
||||
///
|
||||
/// \param val is the data-type of inputs
|
||||
virtual void setMetatypeIn(type_metatype val) {}
|
||||
|
||||
/// \brief Set the data-type (as a meta-type) associated with outputs of this opcode
|
||||
///
|
||||
/// \param val is the data-type of outputs
|
||||
virtual void setMetatypeOut(type_metatype val) {}
|
||||
virtual void setSymbol(const string &nm) { name = nm; } ///< Set the display symbol associated with the op-code
|
||||
public:
|
||||
TypeOp(TypeFactory *t,OpCode opc,const string &n); ///< Constructor
|
||||
|
@ -262,11 +262,11 @@ class HighIntersectTest {
|
||||
void purgeHigh(HighVariable *high); ///< Remove cached intersection tests for a given HighVariable
|
||||
bool testUntiedCallIntersection(HighVariable *tied,HighVariable *untied);
|
||||
public:
|
||||
HighIntersectTest(PcodeOpSet &cCover) : affectingOps(cCover) {}
|
||||
HighIntersectTest(PcodeOpSet &cCover) : affectingOps(cCover) {} ///< Constructor
|
||||
void moveIntersectTests(HighVariable *high1,HighVariable *high2);
|
||||
bool updateHigh(HighVariable *a); ///< Make sure given HighVariable's Cover is up-to-date
|
||||
bool intersection(HighVariable *a,HighVariable *b);
|
||||
void clear(void) { highedgemap.clear(); }
|
||||
void clear(void) { highedgemap.clear(); } ///< Clear any cached tests
|
||||
};
|
||||
|
||||
/// The internal cover is marked as dirty. If \b this is a piece of a VariableGroup, it and all the other
|
||||
|
@ -347,7 +347,7 @@ void ScopeLocal::annotateRawStackPtr(void)
|
||||
/// If the return value is passed back in a location whose address space holds \b this scope's variables,
|
||||
/// assume the return value is unmapped, unless there is a specific alias into the location.
|
||||
/// Mark the range as unmapped.
|
||||
/// \param is the sorted list of alias offsets into the space
|
||||
/// \param alias is the sorted list of alias offsets into the space
|
||||
void ScopeLocal::checkUnaliasedReturn(const vector<uintb> &alias)
|
||||
|
||||
{
|
||||
|
@ -0,0 +1,20 @@
|
||||
<decompilertest>
|
||||
<!--
|
||||
Function accessing a boolean test through the high-bit of a status register via INT_SRIGHT.
|
||||
-->
|
||||
<binaryimage arch="8051:BE:16:default:default">
|
||||
<bytechunk space="CODE" offset="0xa000">
|
||||
e5
|
||||
52b40b005002740122
|
||||
</bytechunk>
|
||||
<symbol space="CODE" offset="0xa000" name="boolless"/>
|
||||
</binaryimage>
|
||||
<script>
|
||||
<com>lo fu boolless</com>
|
||||
<com>dec</com>
|
||||
<com>print C</com>
|
||||
<com>quit</com>
|
||||
</script>
|
||||
<stringmatch name="Boolean thru Less-than #1" min="1" max="1">if \(uINTMEM52 < 0xb\)</stringmatch>
|
||||
<stringmatch name="Boolean thru Less-than #2" min="0" max="0"><< 7</stringmatch>
|
||||
</decompilertest>
|
Loading…
Reference in New Issue
Block a user