ghidra/Ghidra/Features/Decompiler/src/decompile/cpp/comment.hh
2019-03-26 13:46:51 -04:00

247 lines
11 KiB
C++

/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// \file comment.hh
/// \brief A database interface for high-level language comments
#ifndef __CPUI_COMMENT__
#define __CPUI_COMMENT__
#include "address.hh"
class FlowBlock;
class PcodeOp;
class Funcdata;
/// \brief A comment attached to a specific function and code address
///
/// Things contains the actual character data of the comment. It is
/// fundamentally attached to a specific function and to the address of
/// an instruction (within the function's body). Comments
/// can be categorized as a \e header (or not) depending on whether
/// it should be displayed as part of the general description of the
/// function or not. Other properties can be assigned to a comment, to
/// allow the user to specify the subset of all comments they want to display.
class Comment {
friend class CommentDatabaseInternal;
uint4 type; ///< The properties associated with the comment
Address funcaddr; ///< Address of the function containing the comment
Address addr; ///< Address associated with the comment
int4 uniq; ///< Sub-identifier for uniqueness
string text; ///< The body of the comment
public:
/// \brief Possible properties associated with a comment
enum comment_type {
user1 = 1, ///< The first user defined property
user2 = 2, ///< The second user defined property
user3 = 4, ///< The third user defined property
header = 8, ///< The comment should be displayed in the function header
warning = 16, ///< The comment is auto-generated to alert the user
warningheader = 32 ///< The comment is auto-generated and should be in the header
};
Comment(uint4 tp,const Address &fad,
const Address &ad,int4 uq,const string &txt); ///< Constructor
Comment(void) {} ///< Constructor for use with restoreXml
uint4 getType(void) const { return type; } ///< Get the properties associated with the comment
const Address &getFuncAddr(void) const { return funcaddr; } ///< Get the address of the function containing the comment
const Address &getAddr(void) const { return addr; } ///< Get the address to which the instruction is attached
int4 getUniq(void) const { return uniq; } ///< Get the sub-sorting index
const string &getText(void) const { return text; } ///< Get the body of the comment
void saveXml(ostream &s) const; ///< Save the comment to an XML stream
void restoreXml(const Element *el,const AddrSpaceManager *manage); ///< Restore the comment from XML
static uint4 encodeCommentType(const string &name); ///< Convert name string to comment property
static string decodeCommentType(uint4 val); ///< Convert comment property to string
};
/// \brief Compare two Comment pointers
///
/// Comments are ordered first by function, then address,
/// then the sub-sort index.
struct CommentOrder {
bool operator()(const Comment *a,const Comment *b) const; ///< Comparison operator
};
typedef set<Comment *,CommentOrder> CommentSet; ///< A set of comments sorted by function and address
/// \brief An interface to a container of comments
///
/// Comments can be added (and removed) from a database, keying
/// on the function and address the Comment is attached to.
/// The interface can generate a \e begin and \e end iterator covering
/// all Comment objects for a single function.
class CommentDatabase {
public:
CommentDatabase(void) {} ///< Constructor
virtual ~CommentDatabase(void) {} ///< Destructor
virtual void clear(void)=0; ///< Clear all comments from this container
/// \brief Clear all comments matching (one of) the indicated types
///
/// Clearing is restricted to comments belonging to a specific function and matching
/// at least one of the given properties
/// \param fad is the address of the owning function
/// \param tp is a set of one or more properties
virtual void clearType(const Address &fad,uint4 tp)=0;
/// \brief Add a new comment to the container
///
/// \param tp is a set of properties to associate with the new comment (may be zero)
/// \param fad is the address of the function to which the comment belongs
/// \param ad is the address to which the comment is attached
/// \param txt is the body of the comment
virtual void addComment(uint4 tp,const Address &fad,
const Address &ad,const string &txt)=0;
/// \brief Add a new comment to the container, making sure there is no duplicate
///
/// If there is already a comment at the same address with the same body, no
/// new comment is added.
/// \param tp is a set of properties to associate with the new comment (may be zero)
/// \param fad is the address of the function to which the comment belongs
/// \param ad is the address to which the comment is attached
/// \param txt is the body of the comment
/// \return \b true if a new Comment was created, \b false if there was a duplicate
virtual bool addCommentNoDuplicate(uint4 tp,const Address &fad,const Address &ad,const string &txt)=0;
/// \brief Remove the given Comment object from the container
///
/// \param com is the given Comment
virtual void deleteComment(Comment *com)=0;
/// \brief Get an iterator to the beginning of comments for a single function
///
/// \param fad is the address of the function
/// \return the beginning iterator
virtual CommentSet::const_iterator beginComment(const Address &fad) const=0;
/// \brief Get an iterator to the ending of comments for a single function
///
/// \param fad is the address of the function
/// \return the ending iterator
virtual CommentSet::const_iterator endComment(const Address &fad) const=0;
/// \brief Save all comments in the container to an XML stream
///
/// Writes a \<commentdb> tag, with \<comment> sub-tags for each Comment object.
/// \param s is the output stream
virtual void saveXml(ostream &s) const=0;
/// \brief Restore all comments from XML
///
/// \param el is the root \<commentdb> element
/// \param manage is a manager for resolving address space references
virtual void restoreXml(const Element *el,const AddrSpaceManager *manage)=0;
};
/// \brief An in-memory implementation of the CommentDatabase API
///
/// All Comment objects are held in memory in a sorted container. This
/// can be used as stand-alone database of comments, or it can act as a
/// cache for some other container.
class CommentDatabaseInternal : public CommentDatabase {
CommentSet commentset; ///< The sorted set of Comment objects
public:
CommentDatabaseInternal(void); ///< Constructor
virtual ~CommentDatabaseInternal(void);
virtual void clear(void);
virtual void clearType(const Address &fad,uint4 tp);
virtual void addComment(uint4 tp,const Address &fad,
const Address &ad,const string &txt);
virtual bool addCommentNoDuplicate(uint4 tp,const Address &fad,const Address &ad,const string &txt);
virtual void deleteComment(Comment *com);
virtual CommentSet::const_iterator beginComment(const Address &fad) const;
virtual CommentSet::const_iterator endComment(const Address &fad) const;
virtual void saveXml(ostream &s) const;
virtual void restoreXml(const Element *el,const AddrSpaceManager *manage);
};
/// \brief A class for sorting comments into and within basic blocks
///
/// The decompiler endeavors to display comments within the flow of the
/// source code statements it generates. Comments should be placed at or near
/// the statement that encompasses the address of the original instruction
/// to which the comment is attached. This is complicated by the fact that
/// instructions may get removed and transformed during decompilation and even whole
/// basic blocks may get removed.
///
/// This class sorts comments into the basic block that contains
/// it. As statements are emitted, comments can get picked up, in the correct order,
/// even if there is no longer a specific p-code operation at the comment's address.
/// The decompiler maintains information about basic blocks that have been entirely
/// removed, in which case, the user can elect to not display the corresponding comments.
///
/// This class also acts as state for walking comments within a specific basic block or
/// within the header.
class CommentSorter {
public:
enum {
header_basic = 0, ///< Basic header comments
header_unplaced = 1 ///< Comment that can't be placed in code flow
};
private:
/// \brief The sorting key for placing a Comment within a specific basic block
struct Subsort {
int4 index; ///< Either the basic block index or -1 for a function header
uint4 order; ///< The order index within the basic block
uint4 pos; ///< A final count to guarantee a unique sorting
/// \brief Compare comments based on basic block, then position within the block
///
/// \param op2 is the other key to compare with \b this
/// \return \b true if \b this gets ordered before the other key
bool operator<(const Subsort &op2) const {
if (index == op2.index) {
if (order == op2.order)
return (pos < op2.pos);
return (order < op2.order);
}
return (index < op2.index);
}
/// \brief Initialize a key for a header comment
///
/// \param headerType can be either \b header_basic or \b header_unplaced
void setHeader(uint4 headerType) {
index = -1; // -1 indicates a header comment
order = headerType;
}
/// \brief Initialize a key for a basic block position
///
/// \param i is the index of the basic block
/// \param ord is the position within the block
void setBlock(int4 i,uint4 ord) {
index = i;
order = ord;
}
};
map<Subsort,Comment *> commmap; ///< Comments for the current function, sorted by block
mutable map<Subsort,Comment *>::const_iterator start; ///< Iterator to current comment being walked
map<Subsort,Comment *>::const_iterator stop; ///< Last comment in current set being walked
map<Subsort,Comment *>::const_iterator opstop; ///< Statement landmark within current set of comments
bool displayUnplacedComments; ///< True if unplaced comments should be displayed (in the header)
bool findPosition(Subsort &subsort,Comment *comm,const Funcdata *fd); ///< Establish sorting key for a Comment
public:
CommentSorter(void) { displayUnplacedComments = false; } ///< Constructor
void setupFunctionList(uint4 tp,const Funcdata *fd,const CommentDatabase &db,bool displayUnplaced);
void setupBlockList(const FlowBlock *bl); ///< Prepare to walk comments from a single basic block
void setupOpList(const PcodeOp *op); ///< Establish a p-code landmark within the current set of comments
void setupHeader(uint4 headerType); ///< Prepare to walk comments in the header
bool hasNext(void) const { return (start!=opstop); } ///< Return \b true if there are more comments to emit in the current set
Comment *getNext(void) const { Comment *res=(*start).second; ++start; return res; } ///< Advance to the next comment
};
#endif