From 0a23876e01685866ca4bfb04d89c9196c1a99255 Mon Sep 17 00:00:00 2001 From: caheckman <48068198+caheckman@users.noreply.github.com> Date: Wed, 13 Sep 2023 20:38:46 +0000 Subject: [PATCH] GP-3840 Adjustment to FlowBlock::restrictedByConditional --- .../Decompiler/certification.manifest | 1 + .../Decompiler/src/decompile/cpp/Doxyfile | 5 ---- .../src/decompile/cpp/architecture.hh | 4 ++- .../Decompiler/src/decompile/cpp/block.cc | 8 +++++- .../Decompiler/src/decompile/cpp/cover.hh | 10 +++---- .../Decompiler/src/decompile/cpp/database.hh | 8 +++++- .../Decompiler/src/decompile/cpp/fspec.hh | 11 ++++++-- .../Decompiler/src/decompile/cpp/funcdata.cc | 3 +- .../Decompiler/src/decompile/cpp/heritage.cc | 2 +- .../Decompiler/src/decompile/cpp/jumptable.hh | 16 +++++++++-- .../Decompiler/src/decompile/cpp/merge.hh | 4 +-- .../Decompiler/src/decompile/cpp/options.cc | 15 ++++++++++ .../src/decompile/cpp/prettyprint.hh | 4 ++- .../src/decompile/cpp/ruleaction.cc | 14 ++++++++++ .../Decompiler/src/decompile/cpp/sleigh.cc | 6 ++++ .../Decompiler/src/decompile/cpp/subflow.cc | 4 +-- .../Decompiler/src/decompile/cpp/type.hh | 28 ++++++++++++++++--- .../Decompiler/src/decompile/cpp/typeop.hh | 12 ++++++-- .../Decompiler/src/decompile/cpp/variable.hh | 4 +-- .../Decompiler/src/decompile/cpp/varmap.cc | 2 +- .../src/decompile/datatests/boolless.xml | 20 +++++++++++++ 21 files changed, 147 insertions(+), 34 deletions(-) create mode 100644 Ghidra/Features/Decompiler/src/decompile/datatests/boolless.xml diff --git a/Ghidra/Features/Decompiler/certification.manifest b/Ghidra/Features/Decompiler/certification.manifest index 6e4bb55ba1..b9bf25c13e 100644 --- a/Ghidra/Features/Decompiler/certification.manifest +++ b/Ghidra/Features/Decompiler/certification.manifest @@ -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| diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/Doxyfile b/Ghidra/Features/Decompiler/src/decompile/cpp/Doxyfile index 856b540795..6b2dce549e 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/Doxyfile +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/Doxyfile @@ -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 #--------------------------------------------------------------------------- diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh index 98c5d705c4..a7e6af010a 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh @@ -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 /// diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc index ec05214ebd..7eee15f9f8 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc @@ -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;igetImmedDom(); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/cover.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/cover.hh index 04de487fe3..7fd46e6256 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/cover.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/cover.hh @@ -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 opList; // Ops in this set, sorted on block index, then SeqNum::order - vector blockStart; // Index of first op in each non-empty block - bool is_pop; // Has the populate() method been called + vector opList; ///< Ops in this set, sorted on block index, then SeqNum::order + vector 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 diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/database.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/database.hh index bdf162d2af..603532ea4b 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/database.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/database.hh @@ -709,7 +709,13 @@ public: virtual void encode(Encoder &encoder) const=0; ///< Encode \b this as a \ element virtual void decode(Decoder &decoder)=0; ///< Decode \b this Scope from a \ 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 + /// \ 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 diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.hh index 4dd1bcabc9..1144e1b9b7 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.hh @@ -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 &efflist,const Address &addr,int4 size); static int4 lookupRecord(const vector &efflist,int4 listSize,const Address &addr,int4 size); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc index 13e0606775..fc2b235f50 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc @@ -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 diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.cc index 2450485741..f24fef0b65 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.cc @@ -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 diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh index d985052f38..fbe018c848 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh @@ -323,9 +323,19 @@ public: virtual bool sanityCheck(Funcdata *fd,PcodeOp *indop,vector
&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 diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/merge.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/merge.hh index aeb1a84092..9e115edd37 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/merge.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/merge.hh @@ -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; }; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/options.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/options.cc index c193e2d515..8d293ffcb6 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/options.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/options.cc @@ -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 { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/prettyprint.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/prettyprint.hh index 6e7124ccc5..1c3725d6db 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/prettyprint.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/prettyprint.hh @@ -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); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc index 55a3bdd579..33a939790b 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc @@ -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()) { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh.cc index 06b9776c7f..965fbd41e6 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh.cc @@ -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) { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/subflow.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/subflow.cc index 0c42b50107..bde73ee843 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/subflow.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/subflow.cc @@ -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 &outVarnodes) { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh index 5e73969e02..8868e39148 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh @@ -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< &alias) { diff --git a/Ghidra/Features/Decompiler/src/decompile/datatests/boolless.xml b/Ghidra/Features/Decompiler/src/decompile/datatests/boolless.xml new file mode 100644 index 0000000000..749e8f9292 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/datatests/boolless.xml @@ -0,0 +1,20 @@ + + + + +e5 +52b40b005002740122 + + + + +if \(uINTMEM52 < 0xb\) +<< 7 +