diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/Doxyfile b/Ghidra/Features/Decompiler/src/decompile/cpp/Doxyfile index 6c5cb12a1a..e8e78f0f4a 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/Doxyfile +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/Doxyfile @@ -457,7 +457,7 @@ RECURSIVE = NO # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. -EXCLUDE = unify.hh unify.cc rulecompile.hh rulecompile.cc slgh_compile.hh slgh_compile.hh slghpattern.hh slghpattern.cc slghpatexpress.hh slghpatexpress.cc slghsymbol.hh slghsymbol.cc ifacedecomp.hh ifacedecomp.cc ifaceterm.hh ifaceterm.cc codedata.hh codedata.cc semantics.hh semantics.cc grammar.hh grammar.cc callgraph.hh callgraph.cc filemanage.hh filemanage.cc graph.hh graph.cc interface.hh interface.cc loadimage_bfd.hh loadimage_bfd.cc pcodecompile.cc pcodecompile.hh pcodeparse.hh pcodeparse.cc inject_sleigh.hh inject_sleigh.cc context.hh context.cc consolemain.cc sleighexample.cc +EXCLUDE = unify.hh unify.cc rulecompile.hh rulecompile.cc slgh_compile.hh slgh_compile.hh slghpattern.hh slghpattern.cc slghpatexpress.hh slghpatexpress.cc slghsymbol.hh slghsymbol.cc ifacedecomp.hh ifacedecomp.cc ifaceterm.hh ifaceterm.cc codedata.hh codedata.cc semantics.hh semantics.cc grammar.hh grammar.cc callgraph.hh callgraph.cc filemanage.hh filemanage.cc graph.hh graph.cc interface.hh interface.cc loadimage_bfd.hh loadimage_bfd.cc pcodecompile.cc pcodecompile.hh pcodeparse.hh pcodeparse.cc inject_sleigh.hh inject_sleigh.cc context.hh context.cc consolemain.cc sleighexample.cc xml.cc # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc index b67dc33eed..1db2c08607 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc @@ -1161,8 +1161,12 @@ Datatype *TypeOpIntRight::getInputCast(const PcodeOp *op,int4 slot,const CastStr { if (slot == 0) { + const Varnode *vn = op->getIn(0); Datatype *reqtype = op->inputTypeLocal(slot); - Datatype *curtype = op->getIn(slot)->getHigh()->getType(); + Datatype *curtype = vn->getHigh()->getType(); + int4 promoType = castStrategy->intPromotionType(vn); + if (promoType != CastStrategy::NO_PROMOTION && ((promoType & CastStrategy::UNSIGNED_EXTENSION)==0)) + return reqtype; return castStrategy->castStandard(reqtype,curtype,true,true); } return TypeOpBinary::getInputCast(op,slot,castStrategy); @@ -1199,8 +1203,12 @@ Datatype *TypeOpIntSright::getInputCast(const PcodeOp *op,int4 slot,const CastSt { if (slot == 0) { + const Varnode *vn = op->getIn(0); Datatype *reqtype = op->inputTypeLocal(slot); - Datatype *curtype = op->getIn(slot)->getHigh()->getType(); + Datatype *curtype = vn->getHigh()->getType(); + int4 promoType = castStrategy->intPromotionType(vn); + if (promoType != CastStrategy::NO_PROMOTION && ((promoType & CastStrategy::SIGNED_EXTENSION)==0)) + return reqtype; return castStrategy->castStandard(reqtype,curtype,true,true); } return TypeOpBinary::getInputCast(op,slot,castStrategy); @@ -1248,8 +1256,12 @@ TypeOpIntDiv::TypeOpIntDiv(TypeFactory *t) Datatype *TypeOpIntDiv::getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const { + const Varnode *vn = op->getIn(slot); Datatype *reqtype = op->inputTypeLocal(slot); - Datatype *curtype = op->getIn(slot)->getHigh()->getType(); + Datatype *curtype = vn->getHigh()->getType(); + int4 promoType = castStrategy->intPromotionType(vn); + if (promoType != CastStrategy::NO_PROMOTION && ((promoType & CastStrategy::UNSIGNED_EXTENSION)==0)) + return reqtype; return castStrategy->castStandard(reqtype,curtype,true,true); } @@ -1264,8 +1276,12 @@ TypeOpIntSdiv::TypeOpIntSdiv(TypeFactory *t) Datatype *TypeOpIntSdiv::getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const { + const Varnode *vn = op->getIn(slot); Datatype *reqtype = op->inputTypeLocal(slot); - Datatype *curtype = op->getIn(slot)->getHigh()->getType(); + Datatype *curtype = vn->getHigh()->getType(); + int4 promoType = castStrategy->intPromotionType(vn); + if (promoType != CastStrategy::NO_PROMOTION && ((promoType & CastStrategy::SIGNED_EXTENSION)==0)) + return reqtype; return castStrategy->castStandard(reqtype,curtype,true,true); } @@ -1280,12 +1296,13 @@ TypeOpIntRem::TypeOpIntRem(TypeFactory *t) Datatype *TypeOpIntRem::getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const { - if (slot == 0) { - Datatype *reqtype = op->inputTypeLocal(slot); - Datatype *curtype = op->getIn(slot)->getHigh()->getType(); - return castStrategy->castStandard(reqtype,curtype,true,true); - } - return TypeOpBinary::getInputCast(op,slot,castStrategy); + const Varnode *vn = op->getIn(slot); + Datatype *reqtype = op->inputTypeLocal(slot); + Datatype *curtype = vn->getHigh()->getType(); + int4 promoType = castStrategy->intPromotionType(vn); + if (promoType != CastStrategy::NO_PROMOTION && ((promoType & CastStrategy::UNSIGNED_EXTENSION)==0)) + return reqtype; + return castStrategy->castStandard(reqtype,curtype,true,true); } TypeOpIntSrem::TypeOpIntSrem(TypeFactory *t) @@ -1299,12 +1316,13 @@ TypeOpIntSrem::TypeOpIntSrem(TypeFactory *t) Datatype *TypeOpIntSrem::getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const { - if (slot == 0) { - Datatype *reqtype = op->inputTypeLocal(slot); - Datatype *curtype = op->getIn(slot)->getHigh()->getType(); - return castStrategy->castStandard(reqtype,curtype,true,true); - } - return TypeOpBinary::getInputCast(op,slot,castStrategy); + const Varnode *vn = op->getIn(slot); + Datatype *reqtype = op->inputTypeLocal(slot); + Datatype *curtype = vn->getHigh()->getType(); + int4 promoType = castStrategy->intPromotionType(vn); + if (promoType != CastStrategy::NO_PROMOTION && ((promoType & CastStrategy::SIGNED_EXTENSION)==0)) + return reqtype; + return castStrategy->castStandard(reqtype,curtype,true,true); } TypeOpBoolNegate::TypeOpBoolNegate(TypeFactory *t) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/xml.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/xml.hh index 3df7713abe..75e7dd9a9e 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/xml.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/xml.hh @@ -13,6 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +/// \file xml.hh +/// \brief Lightweight (and incomplete) XML parser for marshaling data to and from the decompiler #ifndef __CPUI_XML__ #define __CPUI_XML__ @@ -25,33 +27,40 @@ using namespace std; +/// \brief The \e attributes for a single XML element +/// +/// A container for name/value pairs (of strings) for the formal attributes, as collected during parsing. +/// This object is used to initialize the Element object but is not part of the final, in memory, DOM model. +/// This also holds other properties of the element that are unused in this implementation, +/// including the \e namespace URI. class Attributes { - string *elementname; - string bogus_uri; - string prefix; - vector name; - vector value; + static string bogus_uri; ///< A placeholder for the namespace URI that should be attached to the element +// static string prefix; + string *elementname; ///< The name of the XML element + vector name; ///< List of names for each formal XML attribute + vector value; ///< List of values for each formal XML attribute public: - Attributes(string *el) { elementname = el; } + Attributes(string *el) { elementname = el; } ///< Construct from element name string ~Attributes(void) { for(uint4 i=0;i List; +typedef vector List; ///< A list of XML elements +/// \brief An XML element. A node in the DOM tree. +/// +/// This is the main node for the in-memory representation of the XML (DOM) tree. class Element { - string name; - string content; - vector attr; - vector value; + string name; ///< The (local) name of the element + string content; ///< Character content of the element + vector attr; ///< A list of attribute names for \b this element + vector value; ///< a (corresponding) list of attribute values for \b this element protected: - Element *parent; - List children; + Element *parent; ///< The parent Element (or null) + List children; ///< A list of child Element objects public: - Element(Element *par) { parent = par; } - ~Element(void); - void setName(const string &nm) { name = nm; } + Element(Element *par) { parent = par; } ///< Constructor given a parent Element + ~Element(void); ///< Destructor + void setName(const string &nm) { name = nm; } ///< Set the local name of the element + + /// \brief Append new character content to \b this element + /// + /// \param str is an array of character data + /// \param start is the index of the first character to append + /// \param length is the number of characters to append void addContent(const char *str,int4 start,int4 length) { // for(int4 i=0;i doclist; - map tagmap; + vector doclist; ///< The list of documents held by this container + map tagmap; ///< The map from name to registered XML elements public: - ~DocumentStorage(void); + ~DocumentStorage(void); ///< Destructor + + /// \brief Parse an XML document from the given stream + /// + /// Parsing starts immediately on the stream, attempting to make an in-memory DOM tree. + /// An XmlException is thrown for any parsing error. + /// \param s is the given stream to parse + /// \return the in-memory DOM tree Document *parseDocument(istream &s); + + /// \brief Open and parse an XML file + /// + /// The given filename is opened on the local filesystem and an attempt is made to parse + /// its contents into an in-memory DOM tree. An XmlException is thrown for any parsing error. + /// \param filename is the name of the XML document file + /// \return the in-memory DOM tree Document *openDocument(const string &filename); + + /// \brief Register the given XML Element object under its tag name + /// + /// Only one Element can be stored on \b this object per tag name. + /// \param el is the given XML element void registerTag(const Element *el); + + /// \brief Retrieve a registered XML Element by name + /// + /// \param nm is the XML tag name + /// \return the matching registered Element or null const Element *getTag(const string &nm) const; }; +/// \brief An exception thrown by the XML parser +/// +/// This object holds the error message as passed to the SAX interface callback +/// and is thrown as a formal exception. struct XmlError { - string explain; // Explanatory string - XmlError(const string &s) { explain = s; } + string explain; ///< Explanatory string + XmlError(const string &s) { explain = s; } ///< Constructor }; +/// \brief Start-up the XML parser given a stream and a handler +/// +/// This runs the low-level XML parser. +/// \param i is the given stream to get character data from +/// \param hand is the ContentHandler that stores or processes the XML content events +/// \param dbg is non-zero if the parser should output debug information during its parse +/// \return 0 if there is no error during parsing or a (non-zero) error condition extern int4 xml_parse(istream &i,ContentHandler *hand,int4 dbg=0); + +/// \brief Parse the given XML stream into an in-memory document +/// +/// The stream is parsed using the standard ContentHandler for producing an in-memory +/// DOM representation of the XML document. +/// \param i is the given stream +/// \return the in-memory XML document extern Document *xml_tree(istream &i); + +/// \brief Send the given character array to a stream, escaping characters with special XML meaning +/// +/// This makes the following character substitutions: +/// - '<' => "<" +/// - '>' => ">" +/// - '&' => "&" +/// - '"' => """ +/// - '\'' => "'" +/// +/// \param s is the stream to write to +/// \param str is the given character array to escape extern void xml_escape(ostream &s,const char *str); -// Some helper functions for producing XML +// Some helper functions for writing XML documents directly to a stream + +/// \brief Output an XML attribute name/value pair to stream +/// +/// \param s is the output stream +/// \param attr is the name of the attribute +/// \param val is the attribute value inline void a_v(ostream &s,const string &attr,const string &val) { @@ -175,18 +335,33 @@ inline void a_v(ostream &s,const string &attr,const string &val) s << "\""; } +/// \brief Output the given signed integer as an XML attribute value +/// +/// \param s is the output stream +/// \param attr is the name of the attribute +/// \param val is the given integer value inline void a_v_i(ostream &s,const string &attr,intb val) { s << ' ' << attr << "=\"" << dec << val << "\""; } +/// \brief Output the given unsigned integer as an XML attribute value +/// +/// \param s is the output stream +/// \param attr is the name of the attribute +/// \param val is the given unsigned integer value inline void a_v_u(ostream &s,const string &attr,uintb val) { s << ' ' << attr << "=\"0x" << hex << val << "\""; } +/// \brief Output the given boolean value as an XML attribute +/// +/// \param s is the output stream +/// \param attr is the name of the attribute +/// \param val is the given boolean value inline void a_v_b(ostream &s,const string &attr,bool val) { @@ -198,6 +373,12 @@ inline void a_v_b(ostream &s,const string &attr,bool val) s << "\""; } +/// \brief Read an XML attribute value as a boolean +/// +/// This method is intended to recognize the strings, "true", "yes", and "1" +/// as a \b true value. Anything else is returned as \b false. +/// \param attr is the given XML attribute value (as a string) +/// \return either \b true or \b false inline bool xml_readbool(const string &attr) { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/xml.y b/Ghidra/Features/Decompiler/src/decompile/cpp/xml.y index 6f4c02013d..7c4c60aaac 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/xml.y +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/xml.y @@ -25,11 +25,20 @@ #include #include +string Attributes::bogus_uri("http://unused.uri"); + +/// \brief The XML character scanner +/// +/// Tokenize a byte stream suitably for the main XML parser. The scanner expects an ASCII or UTF-8 +/// encoding. Characters is XML tag and attribute names are restricted to ASCII "letters", but +/// extended UTF-8 characters can be used in any other character data: attribute values, content, comments. class XmlScan { public: + /// \brief Modes of the scanner enum mode { CharDataMode, CDataMode, AttValueSingleMode, AttValueDoubleMode, CommentMode, CharRefMode, NameMode, SNameMode, SingleMode }; + /// \brief Additional tokens returned by the scanner, in addition to byte values 00-ff enum token { CharDataToken = 258, CDataToken = 259, AttValueToken = 260, @@ -40,13 +49,19 @@ public: ElementBraceToken = 265, CommandBraceToken = 266 }; private: - mode curmode; - istream &s; - string *lvalue; // Current string being built - int4 lookahead[4]; - int4 pos; - bool endofstream; // Has end of stream been reached - void clearlvalue(void); + mode curmode; ///< The current scanning mode + istream &s; ///< The stream being scanned + string *lvalue; ///< Current string being built + int4 lookahead[4]; ///< Lookahead into the byte stream + int4 pos; ///< Current position in the lookahead buffer + bool endofstream; ///< Has end of stream been reached + void clearlvalue(void); ///< Clear the current token string + + /// \brief Get the next byte in the stream + /// + /// Maintain a lookahead of 4 bytes at all times so that we can check for special + /// XML character sequences without consuming. + /// \return the next byte value as an integer int4 getxmlchar(void) { char c; int4 ret=lookahead[pos]; @@ -64,40 +79,41 @@ private: pos = (pos+1)&3; return ret; } - int4 next(int4 i) { return lookahead[(pos+i)&3]; } - bool isLetter(int4 val) { return (((val>=0x41)&&(val<=0x5a))||((val>=0x61)&&(val<=0x7a))); } - bool isInitialNameChar(int4 val); - bool isNameChar(int4 val); - bool isChar(int4 val); - int4 scanSingle(void); - int4 scanCharData(void); - int4 scanCData(void); - int4 scanAttValue(int4 quote); - int4 scanCharRef(void); - int4 scanComment(void); - int4 scanName(void); - int4 scanSName(void); + int4 next(int4 i) { return lookahead[(pos+i)&3]; } ///< Peek at the next (i-th) byte without consuming + bool isLetter(int4 val) { return (((val>=0x41)&&(val<=0x5a))||((val>=0x61)&&(val<=0x7a))); } ///< Is the given byte a \e letter + bool isInitialNameChar(int4 val); ///< Is the given byte/character the valid start of an XML name + bool isNameChar(int4 val); ///< Is the given byte/character valid for an XML name + bool isChar(int4 val); ///< Is the given byte/character valid as an XML character + int4 scanSingle(void); ///< Scan for the next token in Single Character mode + int4 scanCharData(void); ///< Scan for the next token is Character Data mode + int4 scanCData(void); ///< Scan for the next token in CDATA mode + int4 scanAttValue(int4 quote); ///< Scan for the next token in Attribute Value mode + int4 scanCharRef(void); ///< Scan for the next token in Character Reference mode + int4 scanComment(void); ///< Scan for the next token in Comment mode + int4 scanName(void); ///< Scan a Name or return single non-name character + int4 scanSName(void); ///< Scan Name, allow white space before public: - XmlScan(istream &t); - ~XmlScan(void); - void setmode(mode m) { curmode = m; } - int4 nexttoken(void); // Interface for bison - string *lval(void) { string *ret = lvalue; lvalue = (string *)0; return ret; } + XmlScan(istream &t); ///< Construct scanner given a stream + ~XmlScan(void); ///< Destructor + void setmode(mode m) { curmode = m; } ///< Set the scanning mode + int4 nexttoken(void); ///< Get the next token + string *lval(void) { string *ret = lvalue; lvalue = (string *)0; return ret; } ///< Return the last \e lvalue string }; +/// \brief A parsed name/value pair struct NameValue { - string *name; - string *value; + string *name; ///< The name + string *value; ///< The value }; -extern int yylex(void); -extern int yyerror(const char *str); -extern void print_content(const string &str); -extern int4 convertEntityRef(const string &ref); -extern int4 convertCharRef(const string &ref); -static XmlScan *global_scan; -static ContentHandler *handler; -extern int yydebug; +extern int yylex(void); ///< Interface to the scanner +extern int yyerror(const char *str); ///< Interface for registering an error in parsing +extern void print_content(const string &str); ///< Send character data to the ContentHandler +extern int4 convertEntityRef(const string &ref); ///< Convert an XML entity to its equivalent character +extern int4 convertCharRef(const string &ref); ///< Convert an XML character reference to its equivalent character +static XmlScan *global_scan; ///< Global reference to the scanner +static ContentHandler *handler; ///< Global reference to the content handler +extern int yydebug; ///< Debug mode %} %union { @@ -233,11 +249,11 @@ int4 XmlScan::scanSingle(void) int4 XmlScan::scanCharData(void) -{ // look for '<' '&' or ']]>' +{ clearlvalue(); lvalue = new string(); - while(next(0) != -1) { + while(next(0) != -1) { // look for '<' '&' or ']]>' if (next(0) == '<') break; if (next(0) == '&') break; if (next(0) == ']') @@ -253,11 +269,11 @@ int4 XmlScan::scanCharData(void) int4 XmlScan::scanCData(void) -{ // Look for "]]>" and non-Char +{ clearlvalue(); lvalue = new string(); - while(next(0) != -1) { + while(next(0) != -1) { // Look for "]]>" and non-Char if (next(0)==']') if (next(1)==']') if (next(2)=='>') @@ -334,7 +350,7 @@ int4 XmlScan::scanComment(void) int4 XmlScan::scanName(void) -{ // Scan a Name or return single non-name character +{ clearlvalue(); lvalue = new string(); @@ -350,7 +366,7 @@ int4 XmlScan::scanName(void) int4 XmlScan::scanSName(void) -{ // Scan Name, allow white space before +{ int4 whitecount = 0; while((next(0)==' ')||(next(0)=='\n')||(next(0)=='\r')||(next(0)=='\t')) { whitecount += 1; @@ -571,7 +587,7 @@ Document *DocumentStorage::parseDocument(istream &s) Document *DocumentStorage::openDocument(const string &filename) -{ // Open and parse an XML file, return Document object +{ ifstream s(filename.c_str()); if (!s) throw XmlError("Unable to open xml document "+filename); @@ -582,13 +598,13 @@ Document *DocumentStorage::openDocument(const string &filename) void DocumentStorage::registerTag(const Element *el) -{ // Register a tag under its name +{ tagmap[el->getName()] = el; } const Element *DocumentStorage::getTag(const string &nm) const -{ // Retrieve a registered tag by name +{ map::const_iterator iter; iter = tagmap.find(nm); @@ -611,7 +627,7 @@ Document *xml_tree(istream &i) void xml_escape(ostream &s,const char *str) -{ // Escape xml tag indicators +{ while(*str!='\0') { if (*str < '?') { if (*str=='<') s << "<";