graph.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. /* ScummVM Tools
  2. *
  3. * ScummVM Tools is the legal property of its developers, whose
  4. * names are too numerous to list here. Please refer to the
  5. * COPYRIGHT file distributed with this source distribution.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  20. */
  21. #ifndef DEC_GRAPH_H
  22. #define DEC_GRAPH_H
  23. #include "instruction.h"
  24. #include "refcounted.h"
  25. #include <ostream>
  26. #include <utility>
  27. #include <vector>
  28. #include <boost/format.hpp>
  29. #include <boost/version.hpp>
  30. #ifdef _MSC_VER
  31. #pragma warning (push)
  32. #pragma warning(disable:4512)
  33. #pragma warning(disable:4100)
  34. #endif
  35. #include <boost/graph/graph_traits.hpp>
  36. #include <boost/graph/adjacency_list.hpp>
  37. #include <boost/graph/graphviz.hpp>
  38. #ifdef _MSC_VER
  39. #pragma warning (pop)
  40. #endif
  41. #include <boost/intrusive_ptr.hpp>
  42. /**
  43. * Enumeration representing the different kinds of groups.
  44. */
  45. enum GroupType {
  46. kNormalGroupType, ///< Normal group.
  47. kWhileCondGroupType, ///< Group is the condition check for a while-loop.
  48. kDoWhileCondGroupType, ///< Group is the condition check for a do-while-loop.
  49. kIfCondGroupType, ///< Group is the condition check for an if.
  50. kBreakGroupType, ///< Group is a break.
  51. kContinueGroupType ///< Group is a continue.
  52. };
  53. struct Group;
  54. /**
  55. * Pointer to a Group.
  56. */
  57. typedef boost::intrusive_ptr<Group> GroupPtr;
  58. /**
  59. * Type representing properties containing a pointer to a Group.
  60. */
  61. typedef boost::property<boost::vertex_name_t, GroupPtr> GroupProperty;
  62. /**
  63. * Type representing properties containing an index, followed by a GroupProperty.
  64. */
  65. typedef boost::property<boost::vertex_index_t, int, GroupProperty> GraphProperty;
  66. /**
  67. * Structure representing whether or not an edge is a jump.
  68. */
  69. struct IsJump {
  70. bool _isJump = false; ///< Whether or not the edge is a jump.
  71. /**
  72. * Parameterless constructor for Group. Required for use with STL and Boost, should not be called manually.
  73. */
  74. IsJump() { _isJump = false; };
  75. /**
  76. * Constructor for IsJump.
  77. *
  78. * @param isJump Whether or not the edge is a jump.
  79. */
  80. IsJump(bool isJump) : _isJump(isJump) {};
  81. /**
  82. * Output edge information to an std::ostream as a graphviz edge property.
  83. *
  84. * @param output The std::ostream to output to.
  85. * @param isJump The IsJump to output.
  86. * @return The std::ostream used for output.
  87. */
  88. friend std::ostream &operator<<(std::ostream &output, IsJump isJump) {
  89. if (isJump._isJump)
  90. output << "empty";
  91. else
  92. output << "normal";
  93. return output;
  94. }
  95. };
  96. namespace boost {
  97. /**
  98. * Property writer for the isJump property.
  99. */
  100. template <class Name>
  101. class arrowheadWriter {
  102. public:
  103. /**
  104. * Constructor for arrowheadWriter.
  105. *
  106. * @param _name The name of the attribute to use.
  107. */
  108. arrowheadWriter(Name _name) : name(_name) {}
  109. /**
  110. * Outputs the arrowhead edge property.
  111. *
  112. * @param out The std::ostream to output to.
  113. * @param v The vertex or edge to output the attribute for.
  114. */
  115. template <class VertexOrEdge>
  116. void operator()(std::ostream& out, const VertexOrEdge& v) const {
  117. out << "[arrowhead=\"" << get(name, v) << "\"]";
  118. }
  119. private:
  120. Name name; ///< The name of the attribute to use.
  121. };
  122. /**
  123. * Creates an arrowhead property writer.
  124. *
  125. * @param _name The name of the attribute to use.
  126. */
  127. template <class Name>
  128. inline arrowheadWriter<Name>
  129. makeArrowheadWriter(Name n) {
  130. return arrowheadWriter<Name>(n);
  131. }
  132. } // End of namespace boost
  133. typedef boost::property<boost::edge_attribute_t, IsJump> EdgeProperty;
  134. /**
  135. * Type used for the code flow graph.
  136. */
  137. typedef boost::adjacency_list<boost::setS, boost::listS, boost::bidirectionalS, GraphProperty, EdgeProperty> Graph;
  138. /**
  139. * Type representing a vertex in the graph.
  140. */
  141. typedef Graph::vertex_descriptor GraphVertex;
  142. /**
  143. * Type representing an iterator for vertices.
  144. */
  145. typedef Graph::vertex_iterator VertexIterator;
  146. /**
  147. * Type representing an edge in the graph.
  148. */
  149. typedef Graph::edge_descriptor GraphEdge;
  150. /**
  151. * Type representing an iterator for outgoing edges.
  152. */
  153. typedef Graph::out_edge_iterator OutEdgeIterator;
  154. /**
  155. * Type representing an iterator for ingoing edges.
  156. */
  157. typedef Graph::in_edge_iterator InEdgeIterator;
  158. /**
  159. * Type representing a range of vertices from boost::vertices.
  160. */
  161. typedef std::pair<VertexIterator, VertexIterator> VertexRange;
  162. /**
  163. * Type representing a range of edges from boost::out_edges.
  164. */
  165. typedef std::pair<OutEdgeIterator, OutEdgeIterator> OutEdgeRange;
  166. /**
  167. * Type representing a range of edges from boost::in_edges.
  168. */
  169. typedef std::pair<InEdgeIterator, InEdgeIterator> InEdgeRange;
  170. /**
  171. * Structure representing a line of code.
  172. */
  173. struct CodeLine {
  174. std::string _line = "0"; ///< The line of code.
  175. bool _unindentBefore = false; ///< Whether or not to add an indentation level before outputting the line.
  176. bool _indentAfter = false; ///< Whether or not to remove an indentation level after outputting the line.
  177. /**
  178. * Constructor for CodeLine.
  179. *
  180. * @param line The line of code.
  181. * @param unindentBefore Whether or not to remove an indentation level before the line. Defaults to false.
  182. * @param indentAfter Whether or not to add an indentation level after the line. Defaults to false.
  183. */
  184. CodeLine(const std::string& line, bool unindentBefore, bool indentAfter) {
  185. _line = line;
  186. _unindentBefore = unindentBefore;
  187. _indentAfter = indentAfter;
  188. }
  189. };
  190. /**
  191. * Weak references to groups ending else blocks.
  192. */
  193. typedef std::vector<Group *> ElseEnds;
  194. /**
  195. * Iterator type for ElseEnds
  196. */
  197. typedef ElseEnds::iterator ElseEndIterator;
  198. /**
  199. * Structure representing a group of instructions.
  200. */
  201. struct Group : public RefCounted {
  202. public:
  203. GraphVertex _vertex; ///< Vertex the group belongs to.
  204. InstIterator start_; ///< First instruction in the group.
  205. InstIterator end_; ///< Last instruction in the group.
  206. int _stackLevel; ///< Level of the stack upon entry.
  207. GroupType _type; ///< Type of the group.
  208. bool _startElse; ///< Group is start of an else block.
  209. ElseEnds _endElse; ///< Group is end of an else block.
  210. Group *_prev; ///< Pointer to the previous group, when ordered by address. Used for short-circuit analysis.
  211. Group *_next; ///< Pointer to the next group, when ordered by address.
  212. std::vector<CodeLine> _code; ///< Container for decompiled lines of code.
  213. bool _coalescedElse; ///< True if an else starting has been coalesced with another block (e.g. "else if"). If true, an else starting here should not be closed explicitly, but left to the other block.
  214. /**
  215. * Parameterless constructor for Group. Required for use with STL and Boost, should not be called manually.
  216. */
  217. Group() : _stackLevel(-1), _type(kNormalGroupType) { }
  218. /**
  219. * Constructor for Group.
  220. *
  221. * @param v The vertex the group belongs to.
  222. * @param start First instruction in the group.
  223. * @param end Last instruction in the group.
  224. * @param prev Pointer to the previous group, when ordered by address.
  225. */
  226. Group(GraphVertex v,InstIterator start, InstIterator end, GroupPtr prev) {
  227. _vertex = v;
  228. start_ = start;
  229. end_ = end;
  230. _stackLevel = -1;
  231. _type = kNormalGroupType;
  232. _prev = prev.get();
  233. _startElse = false;
  234. if (_prev != NULL)
  235. _prev->_next = this;
  236. _next = NULL;
  237. _coalescedElse = false;
  238. }
  239. /**
  240. * Output a group to an std::ostream as a graphviz label.
  241. *
  242. * @param output The std::ostream to output to.
  243. * @param group The Group to output.
  244. * @return The std::ostream used for output.
  245. */
  246. friend std::ostream &operator<<(std::ostream &output, GroupPtr group) {
  247. output << "{Block type: ";
  248. switch(group->_type) {
  249. case kNormalGroupType:
  250. output << "Normal";
  251. break;
  252. case kWhileCondGroupType:
  253. output << "While condition";
  254. break;
  255. case kDoWhileCondGroupType:
  256. output << "Do-while condition";
  257. break;
  258. case kIfCondGroupType:
  259. output << "If condition";
  260. break;
  261. case kBreakGroupType:
  262. output << "Break";
  263. break;
  264. case kContinueGroupType:
  265. output << "Continue";
  266. break;
  267. }
  268. output << "\\n";
  269. output << "Expected stack level: " << group->_stackLevel << "\\n";
  270. if (group->_startElse)
  271. output << "Start of else\\n";
  272. for (ElseEndIterator it = group->_endElse.begin(); it != group->_endElse.end(); ++it) {
  273. output << boost::format("End of else at %08x\\n") % (*(*it)->start_)->_address;
  274. }
  275. output << "|";
  276. ConstInstIterator inst = group->start_;
  277. do {
  278. std::stringstream stream;
  279. stream << *inst;
  280. #if (BOOST_VERSION >= 104500)
  281. output << stream.str();
  282. #else
  283. std::string s = stream.str();
  284. for (std::string::iterator it = s.begin(); it != s.end(); ++it)
  285. if (*it == '"')
  286. output << "\\\"";
  287. else if (*it == '|')
  288. output << "\\|";
  289. else if (*it == '{')
  290. output << "\\{";
  291. else if (*it == '}')
  292. output << "\\}";
  293. else
  294. output << *it;
  295. #endif
  296. output << "\\n";
  297. } while (inst++ != group->end_);
  298. output << "}";
  299. return output;
  300. }
  301. };
  302. class Engine;
  303. /**
  304. * Type used to set properties for dot output.
  305. */
  306. struct GraphProperties {
  307. private:
  308. Engine *_engine; ///< Pointer to the engine containing function information for the script.
  309. const Graph* _g; ///< Pointer to the to the graph for the script.
  310. public:
  311. GraphProperties(const GraphProperties& rhs)
  312. {
  313. *this = rhs;
  314. }
  315. GraphProperties& operator = (const GraphProperties& rhs)
  316. {
  317. if (this != &rhs)
  318. {
  319. _engine = rhs._engine;
  320. _g = rhs._g;
  321. }
  322. return *this;
  323. }
  324. /**
  325. * Constructor for GraphProperties.
  326. *
  327. * @param engine Pointer to the engine containing function information for the script.
  328. * @param g Const reference to the graph for the script.
  329. */
  330. GraphProperties(Engine *engine, const Graph &g) : _engine(engine), _g(&g) {
  331. }
  332. /**
  333. * Called by write_graphviz from Boost.Graph to print properties of the graph.
  334. *
  335. * @param out The std::ostream write_graphviz is writing to.
  336. */
  337. void operator()(std::ostream& out) const;
  338. };
  339. #endif